Merge branch 'master' of github.com:backstage/backstage into improve-errors
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Pass on plugin database management instance that is now required by the scaffolder plugin.
|
||||
|
||||
To apply this change to an existing application, add the following to `src/plugins/scaffolder.ts`:
|
||||
|
||||
```diff
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
+ database,
|
||||
}: PluginEnvironment) {
|
||||
|
||||
// ...omitted...
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
templaters,
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
entityClient,
|
||||
+ database,
|
||||
});
|
||||
}
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
---
|
||||
|
||||
Export _api_ (Client, API, ref) from the catalog import plugin.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin as `scaffolderPlugin`. The template list page (`/create`) is exported as the `TemplateIndexPage` extension, and the templating page itself is exported as `TemplatePage`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
---
|
||||
|
||||
1. Added option to use Azure Blob Storage as a choice to store the static generated files for TechDocs.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': patch
|
||||
---
|
||||
|
||||
Fix snooze quarter option
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-cost-insights': minor
|
||||
---
|
||||
|
||||
add alert hooks
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-circleci': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `circleCIPlugin`, the entity page content as `EntityCircleCIContent`, and entity conditional as `isCircleCIAvailable`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update `create-plugin` template to use the new composability API, by switching to exporting a single routable extension component.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search': minor
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `searchPlugin`, and page as `SearchPage`. Due to the old router component also being called `SearchPage`, this is a breaking change. The old page component is now exported as `Router`, which can be used to maintain the old behavior.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-graphiql': patch
|
||||
---
|
||||
|
||||
Finalized composability API migration, now exporting the plugin as `graphiqlPlugin`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Add className to the SidebarItem
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Update `WarningPanel` component to use accordion-style expansion
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
Display owner and system as entity page links in the tables of the `api-docs`
|
||||
plugin.
|
||||
|
||||
Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to
|
||||
`@backstage/plugin-catalog-react` and export it from there to use it by other
|
||||
plugins.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/theme': patch
|
||||
---
|
||||
|
||||
Updates warning text color to align to updated `WarningPanel` styling
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `catalogImportPlugin`, and the page as `CatalogImportPage`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-lighthouse': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `lighthousePlugin`, the top-level page as `LighthousePage`, the entity card as `EntityLastLighthouseAuditCard`, and the entity content as `EntityLighthouseContent`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Don't respond to a request twice if an entity has not been found.
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Updated the `rootLogger` in `@backstage/backend-common` to support custom logging options. This is useful when you want to make some changes without re-implementing the entire logger and calling `setRootLogger` or `logger.configure`. For example you can add additional `defaultMeta` tags to each log entry. The following changes are included:
|
||||
|
||||
- Added `createRootLogger` which accepts winston `LoggerOptions`. These options allow overriding the default keys.
|
||||
|
||||
Example Usage:
|
||||
|
||||
```ts
|
||||
// Create the logger
|
||||
const logger = createRootLogger({
|
||||
defaultMeta: { appName: 'backstage', appEnv: 'prod' },
|
||||
});
|
||||
|
||||
// Add a custom logger transport
|
||||
logger.add(new MyCustomTransport());
|
||||
|
||||
const config = await loadBackendConfig({
|
||||
argv: process.argv,
|
||||
logger: getRootLogger(), // already set to new logger instance
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-cloudbuild': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `cloudbuildPlugin`, the entity content as `EntityCloudbuildContent`, the entity conditional as `isCloudbuildAvailable`, and entity cards as `EntityLatestCloudbuildRunCard` and `EntityLatestCloudbuildsForBranchCard`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin as `userSettingsPlugin` and the page as `UserSettingsPage`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-register-component': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `registerComponentPlugin`, and page as `RegisterComponentPage`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
---
|
||||
|
||||
Adds a new optional `links` metadata field to the Entity class within the `catalog-model` package (as discussed in [[RFC] Entity Links](https://github.com/backstage/backstage/issues/3787)). This PR adds support for the entity links only. Follow up PR's will introduce the UI component to display them.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Add `children` option to `addPage`, which will be rendered as the children of the `Route`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Introduced `v2` Scaffolder REST API, which uses an implementation that is database backed, making the scaffolder instances stateless. The `createRouter` function now requires a `PluginDatabaseManager` instance to be passed in, commonly available as `database` in the plugin environment in the backend.
|
||||
|
||||
This API should be considered unstable until used by the scaffolder frontend.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Attempt to fix windows test errors in master
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
---
|
||||
|
||||
Replace `yup` with `ajv`, for validation of catalog entities.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fixed module resolution of external libraries during backend development. Modules used to be resolved relative to the backend entrypoint, but are now resolved relative to each individual module.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'@backstage/core': minor
|
||||
---
|
||||
|
||||
Closes #3556
|
||||
The scroll bar of collapsed sidebar is now hidden without full screen.
|
||||
|
||||

|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-org': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `orgPlugin`, and the entity cards as `EntityGroupProfileCard`, `EntityMembersListCard`, `EntityOwnershipCard`, and `EntityUserProfileCard`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Bump `config-loader` to `ajv` 7, to enable v7 feature use elsewhere
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/dev-utils': patch
|
||||
---
|
||||
|
||||
Added `path` option to `addPage` that can be used to set a specific path for the page rather than a generated one. Also omit sidebar item altogether if `title` option is not set.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/integration': patch
|
||||
---
|
||||
|
||||
Properly forward errors that occur when looking up GitLab project IDs.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/config-loader': patch
|
||||
---
|
||||
|
||||
Each piece of the configuration schema is now validated upfront, in order to produce more informative errors.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-app-backend': patch
|
||||
---
|
||||
|
||||
Failures to load the frontend configuration schema now throws an error that includes more context and instructions for how to fix the issue.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `techdocsPlugin`, the top-level page as `TechdocsPage`, and the entity content as `EntityTechdocsContent`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Add a `prop` union for `SignInPage` that allows it to be used for just a single provider, with inline errors, and optionally with automatic sign-in.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Set explicit content-type in error handler responses.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Slight refactoring in support of a future search implementation in `UrlReader`. Mostly moving code around.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Add check for outdated/duplicate packages to yarn start
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-pagerduty': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `pagerDutyPlugin`, entity card as `EntityPagerDutyCard`, and entity conditional as `isPagerDutyAvailable`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-gcp-projects': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin as `gcpProjectsPlugin` and page as `GcpProjectsPage`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Throw `NotAllowedError` when registering locations with entities of disallowed kinds
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
Added `mountedRoutes` option to `wrapInTestApp`, allowing routes to be associated to concrete paths to make `useRouteRef` usable in tested components.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-jenkins': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `jenkinsPlugin`, the entity content as `EntityJenkinsContent`, the entity conditional as `isJenkinsAvailable`, and the entity card as `EntityLatestJenkinsRunCard`.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-fossa': minor
|
||||
---
|
||||
|
||||
Port FOSSA plugin to new extension model.
|
||||
|
||||
If you are using the FOSSA plugin adjust the plugin import from `plugin` to
|
||||
`fossaPlugin` and replace `<FossaCard entity={...} ...>` with `<EntityFossaCard />`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin as `apiDocsPlugin`, index page as `ApiExplorerPage`, and entity page cards as `EntityApiDefinitionCard`, `EntityConsumedApisCard`, `EntityConsumingComponentsCard`, `EntityProvidedApisCard`, and `EntityProvidingComponentsCard`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Finalize migration to new composability API, with the plugin instance now exported `catalogPlugin`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-github-actions': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `githubActionsPlugin`, the entity content as `EntityGithubActionsContent`, entity conditional as `isGithubActionsAvailable`, and entity cards as `EntityLatestGithubActionRunCard`, `EntityLatestGithubActionsForBranchCard`, and `EntityRecentGithubActionsRunsCard`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-tech-radar': patch
|
||||
---
|
||||
|
||||
Fix mapping RadarEntry and Entry for moved and url attributes
|
||||
Fix clicking of links in the radar legend
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-newrelic': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `newRelicPlugin`, and the root page as `NewRelicPage`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Fix check that determines whether popup was closed or the messaging was misconfigured.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `kubernetesPlugin` and entity content as `EntityKubernetesContent`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-sonarqube': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin as `sonarQubePlugin` and card as `EntitySonarQubeCard`.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
---
|
||||
|
||||
Introduce json schema variants of the `yup` validation schemas
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kafka': patch
|
||||
---
|
||||
|
||||
Migrate to new composability API, exporting the plugin instance as `kafkaPlugin`, entity content as `EntityKafkaContent`, and entity conditional as `isKafkaAvailable`.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
# Repo visibility for GitLab and BitBucket repos
|
||||
|
||||
**NOTE: This changes default repo visibility from `private` to `public` for GitLab and BitBucket** which
|
||||
is consistent with the GitHub default. If you were counting on `private` visibility, you'll need to update
|
||||
your scaffolder config to use `private`.
|
||||
|
||||
This adds repo visibility feature parity with GitHub for GitLab and BitBucket.
|
||||
|
||||
To configure the repo visibility, set scaffolder._type_.visibility as in this example:
|
||||
|
||||
```yaml
|
||||
scaffolder:
|
||||
github:
|
||||
visibility: private # 'public' or 'internal' or 'private' (default is 'public')
|
||||
gitlab:
|
||||
visibility: public # 'public' or 'internal' or 'private' (default is 'public')
|
||||
bitbucket:
|
||||
visibility: public # 'public' or 'private' (default is 'public')
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-welcome': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin as `welcomePlugin` and the page as `WelcomePage`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Refactored route response handling to use more explicit types and throw errors.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
---
|
||||
|
||||
dir preparer will use URL Reader in its implementation.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Enhance API calls to support trapping 500 errors from techdocs-backend
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings': patch
|
||||
---
|
||||
|
||||
Keep the Pin Sidebar setting visible on small screens.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Fixed type inference of `createRouteRef`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-gitops-profiles': patch
|
||||
---
|
||||
|
||||
Migrated to new composability API, exporting the plugin instance as `gitopsProfilesPlugin` and pages as `GitopsProfilesClusterListPage`, `GitopsProfilesClusterPage`, and `GitopsProfilesCreatePage`.
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
'@backstage/plugin-catalog-import': patch
|
||||
'@backstage/plugin-circleci': patch
|
||||
'@backstage/plugin-cloudbuild': patch
|
||||
'@backstage/plugin-github-actions': patch
|
||||
'@backstage/plugin-jenkins': patch
|
||||
'@backstage/plugin-kafka': patch
|
||||
'@backstage/plugin-lighthouse': patch
|
||||
'@backstage/plugin-org': patch
|
||||
'@backstage/plugin-register-component': patch
|
||||
'@backstage/plugin-rollbar': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-search': patch
|
||||
'@backstage/plugin-sentry': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
'@backstage/dev-utils': patch
|
||||
---
|
||||
|
||||
Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
The scaffolder is updated to generate a unique workspace directory inside the temp folder. This directory is cleaned up by the job processor after each run.
|
||||
|
||||
The prepare/template/publish steps have been refactored to operate on known directories, `template/` and `result/`, inside the temporary workspace path.
|
||||
|
||||
Updated preparers to accept the template url instead of the entire template. This is done primarily to allow for backwards compatibility between v1 and v2 scaffolder templates.
|
||||
|
||||
Fixes broken GitHub actions templating in the Create React App template.
|
||||
|
||||
#### For those with **custom** preparers, templates, or publishers
|
||||
|
||||
The preparer interface has changed, the prepare method now only takes a single argument, and doesn't return anything. As part of this change the preparers were refactored to accept a URL pointing to the target directory, rather than computing that from the template entity.
|
||||
|
||||
The `workingDirectory` option was also removed, and replaced with a `workspacePath` option. The difference between the two is that `workingDirectory` was a place for the preparer to create temporary directories, while the `workspacePath` is the specific folder were the entire templating process for a single template job takes place. Instead of returning a path to the folder were the prepared contents were placed, the contents are put at the `<workspacePath>/template` path.
|
||||
|
||||
```diff
|
||||
type PreparerOptions = {
|
||||
- workingDirectory?: string;
|
||||
+ /**
|
||||
+ * Full URL to the directory containg template data
|
||||
+ */
|
||||
+ url: string;
|
||||
+ /**
|
||||
+ * The workspace path that will eventually be the the root of the new repo
|
||||
+ */
|
||||
+ workspacePath: string;
|
||||
logger: Logger;
|
||||
};
|
||||
|
||||
-prepare(template: TemplateEntityV1alpha1, opts?: PreparerOptions): Promise<string>
|
||||
+prepare(opts: PreparerOptions): Promise<void>;
|
||||
```
|
||||
|
||||
Instead of returning a path to the folder were the templaters contents were placed, the contents are put at the `<workspacePath>/result` path. All templaters now also expect the source template to be present in the `template` directory within the `workspacePath`.
|
||||
|
||||
```diff
|
||||
export type TemplaterRunOptions = {
|
||||
- directory: string;
|
||||
+ workspacePath: string;
|
||||
values: TemplaterValues;
|
||||
logStream?: Writable;
|
||||
dockerClient: Docker;
|
||||
};
|
||||
|
||||
-public async run(options: TemplaterRunOptions): Promise<TemplaterRunResult>
|
||||
+public async run(options: TemplaterRunOptions): Promise<void>
|
||||
```
|
||||
|
||||
Just like the preparer and templaters, the publishers have also switched to using `workspacePath`. The root of the new repo is expected to be located at `<workspacePath>/result`.
|
||||
|
||||
```diff
|
||||
export type PublisherOptions = {
|
||||
values: TemplaterValues;
|
||||
- directory: string;
|
||||
+ workspacePath: string;
|
||||
logger: Logger;
|
||||
};
|
||||
```
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': minor
|
||||
'@backstage/create-app': minor
|
||||
---
|
||||
|
||||
`@backstage/plugin-catalog` stopped exporting hooks and helpers for other
|
||||
plugins. They are migrated to `@backstage/plugin-catalog-react`.
|
||||
Change both your dependencies and imports to the new package.
|
||||
@@ -3,6 +3,7 @@ name: E2E Test Linux
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.changeset/**'
|
||||
- 'contrib/**'
|
||||
- 'docs/**'
|
||||
- 'microsite/**'
|
||||
|
||||
@@ -74,8 +74,6 @@ organization:
|
||||
|
||||
# Reference documentation http://backstage.io/docs/features/techdocs/configuration
|
||||
techdocs:
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
builder: 'local' # Alternatives - 'external'
|
||||
generators:
|
||||
techdocs: 'docker' # Alternatives - 'local'
|
||||
|
||||
@@ -13,15 +13,6 @@ configuration options for TechDocs.
|
||||
# File: app-config.yaml
|
||||
|
||||
techdocs:
|
||||
# TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
|
||||
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
|
||||
# Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
|
||||
# to serve files from either a local directory or an External storage provider.
|
||||
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
|
||||
# generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to
|
||||
# spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of).
|
||||
# You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running
|
||||
@@ -101,4 +92,15 @@ techdocs:
|
||||
# https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json
|
||||
accountKey:
|
||||
$env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY
|
||||
|
||||
# (Optional and Legacy) TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
|
||||
# You don't have to specify this anymore.
|
||||
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
|
||||
# (Optional and Legacy) Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
|
||||
# to serve files from either a local directory or an External storage provider.
|
||||
# You don't have to specify this anymore.
|
||||
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
```
|
||||
|
||||
@@ -80,6 +80,10 @@ Create a `/docs` folder in the root of the project with at least an `index.md`
|
||||
file. _(If you add more markdown files, make sure to update the nav in the
|
||||
mkdocs.yml file to get a proper navigation for your documentation.)_
|
||||
|
||||
> Note - Although `docs` is a popular directory name for storing documentation,
|
||||
> it can be renamed to something else and can be configured by `mkdocs.yml`. See
|
||||
> https://www.mkdocs.org/user-guide/configuration/#docs_dir
|
||||
|
||||
The `docs/index.md` can for example have the following content:
|
||||
|
||||
```md
|
||||
|
||||
@@ -150,26 +150,10 @@ app. Now let us tweak some configurations to suit your needs.
|
||||
**See [TechDocs Configuration Options](configuration.md) for complete
|
||||
configuration reference.**
|
||||
|
||||
### Setting TechDocs URLs
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
```
|
||||
|
||||
`requestUrl` is used by TechDocs frontend plugin to discover `techdocs-backend`
|
||||
endpoints, and the `storageUrl` is another endpoint in `techdocs-backend` which
|
||||
acts as a middleware between TechDocs and the storage (where the static
|
||||
generated docs site are stored). These default values should mostly work for
|
||||
you. These options will soon be optional to set.
|
||||
|
||||
### Should TechDocs Backend generate docs?
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
builder: 'local'
|
||||
```
|
||||
|
||||
@@ -196,8 +180,6 @@ out Backstage for the first time. At a later time, review
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
requestUrl: http://localhost:7000/api/techdocs/
|
||||
builder: 'local'
|
||||
publisher:
|
||||
type: 'local'
|
||||
@@ -219,6 +201,9 @@ no config is provided.
|
||||
|
||||
```yaml
|
||||
techdocs:
|
||||
builder: 'local'
|
||||
publisher:
|
||||
type: 'local'
|
||||
generators:
|
||||
techdocs: local
|
||||
```
|
||||
|
||||
@@ -90,7 +90,7 @@ $ docker build -t example-deployment .
|
||||
To run the image locally you can run:
|
||||
|
||||
```sh
|
||||
$ docker run -p -it 7000:7000 example-deployment
|
||||
$ docker run -it -p 7000:7000 example-deployment
|
||||
```
|
||||
|
||||
You should then start to get logs in your terminal, and then you can open your
|
||||
|
||||
+2
-1
@@ -37,11 +37,12 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"**/@roadiehq/**/@backstage/core": "*",
|
||||
"**/@roadiehq/**/@backstage/plugin-catalog": "*",
|
||||
"**/@roadiehq/**/@backstage/catalog-model": "*"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.11.0",
|
||||
"@changesets/cli": "^2.14.0",
|
||||
"@octokit/openapi-types": "^2.2.0",
|
||||
"@spotify/eslint-config-oss": "^1.0.1",
|
||||
"@spotify/prettier-config": "^9.0.0",
|
||||
|
||||
@@ -1,5 +1,81 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9d6ef14bc: Migrated to new composability API, exporting the plugin instance as `rollbarPlugin`, the entity page content as `EntityRollbarContent`, and entity conditional as `isRollbarAvailable`. Updated the `EntityPage` for the `example-app` to include a composite `ErrorsSwitcher` component that works with both `Sentry` & `Rollbar`. Also removed the unused and undocumented `RollbarHome` related components.
|
||||
- Updated dependencies [ceef4dd89]
|
||||
- Updated dependencies [720149854]
|
||||
- Updated dependencies [19172f5a9]
|
||||
- Updated dependencies [4c6a6dddd]
|
||||
- Updated dependencies [398e1f83e]
|
||||
- Updated dependencies [87b189d00]
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [b712841d6]
|
||||
- Updated dependencies [a5628df40]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [bc5082a00]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [e44925723]
|
||||
- Updated dependencies [b37501a3d]
|
||||
- Updated dependencies [9d6ef14bc]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [e9aab60c7]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [0269f4fd9]
|
||||
- Updated dependencies [19fe61c27]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [a08c4b0b0]
|
||||
- Updated dependencies [bc5082a00]
|
||||
- Updated dependencies [bc5082a00]
|
||||
- Updated dependencies [b37501a3d]
|
||||
- Updated dependencies [90c8f20b9]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [8dfdec613]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [de98c32ed]
|
||||
- Updated dependencies [806929fe2]
|
||||
- Updated dependencies [019fe39a0]
|
||||
- Updated dependencies [019fe39a0]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/plugin-catalog-import@0.3.7
|
||||
- @backstage/plugin-scaffolder@0.4.2
|
||||
- @backstage/plugin-cost-insights@0.8.0
|
||||
- @backstage/cli@0.6.0
|
||||
- @backstage/plugin-graphiql@0.2.7
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-api-docs@0.4.4
|
||||
- @backstage/plugin-catalog@0.3.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/plugin-org@0.3.5
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/plugin-lighthouse@0.2.9
|
||||
- @backstage/plugin-techdocs@0.5.5
|
||||
- @backstage/plugin-user-settings@0.2.5
|
||||
- @backstage/catalog-model@0.7.1
|
||||
- @backstage/plugin-rollbar@0.2.9
|
||||
- @backstage/plugin-gcp-projects@0.2.4
|
||||
- @backstage/plugin-tech-radar@0.3.4
|
||||
- @backstage/plugin-welcome@0.2.5
|
||||
- @backstage/plugin-explore@0.2.4
|
||||
- @backstage/plugin-circleci@0.2.7
|
||||
- @backstage/plugin-cloudbuild@0.2.8
|
||||
- @backstage/plugin-github-actions@0.3.1
|
||||
- @backstage/plugin-jenkins@0.3.8
|
||||
- @backstage/plugin-kafka@0.2.1
|
||||
- @backstage/plugin-register-component@0.2.8
|
||||
- @backstage/plugin-search@0.2.7
|
||||
- @backstage/plugin-sentry@0.3.4
|
||||
- @backstage/plugin-gitops-profiles@0.2.4
|
||||
- @backstage/plugin-kubernetes@0.3.8
|
||||
- @backstage/plugin-newrelic@0.2.4
|
||||
- @backstage/plugin-pagerduty@0.2.7
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+33
-33
@@ -1,41 +1,41 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.13",
|
||||
"version": "0.2.14",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-api-docs": "^0.4.3",
|
||||
"@backstage/plugin-catalog": "^0.2.14",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/plugin-catalog-import": "^0.3.6",
|
||||
"@backstage/plugin-circleci": "^0.2.6",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.7",
|
||||
"@backstage/plugin-cost-insights": "^0.7.0",
|
||||
"@backstage/plugin-explore": "^0.2.3",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.3",
|
||||
"@backstage/plugin-github-actions": "^0.3.0",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.3",
|
||||
"@backstage/plugin-graphiql": "^0.2.6",
|
||||
"@backstage/plugin-org": "^0.3.4",
|
||||
"@backstage/plugin-jenkins": "^0.3.6",
|
||||
"@backstage/plugin-kafka": "^0.2.0",
|
||||
"@backstage/plugin-kubernetes": "^0.3.7",
|
||||
"@backstage/plugin-lighthouse": "^0.2.8",
|
||||
"@backstage/plugin-newrelic": "^0.2.3",
|
||||
"@backstage/plugin-pagerduty": "0.2.6",
|
||||
"@backstage/plugin-register-component": "^0.2.7",
|
||||
"@backstage/plugin-rollbar": "^0.2.8",
|
||||
"@backstage/plugin-scaffolder": "^0.4.1",
|
||||
"@backstage/plugin-sentry": "^0.3.3",
|
||||
"@backstage/plugin-search": "^0.2.6",
|
||||
"@backstage/plugin-tech-radar": "^0.3.3",
|
||||
"@backstage/plugin-techdocs": "^0.5.4",
|
||||
"@backstage/plugin-user-settings": "^0.2.4",
|
||||
"@backstage/plugin-welcome": "^0.2.4",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-api-docs": "^0.4.4",
|
||||
"@backstage/plugin-catalog": "^0.3.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@backstage/plugin-catalog-import": "^0.3.7",
|
||||
"@backstage/plugin-circleci": "^0.2.7",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.8",
|
||||
"@backstage/plugin-cost-insights": "^0.8.0",
|
||||
"@backstage/plugin-explore": "^0.2.4",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.4",
|
||||
"@backstage/plugin-github-actions": "^0.3.1",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.4",
|
||||
"@backstage/plugin-graphiql": "^0.2.7",
|
||||
"@backstage/plugin-org": "^0.3.5",
|
||||
"@backstage/plugin-jenkins": "^0.3.8",
|
||||
"@backstage/plugin-kafka": "^0.2.1",
|
||||
"@backstage/plugin-kubernetes": "^0.3.8",
|
||||
"@backstage/plugin-lighthouse": "^0.2.9",
|
||||
"@backstage/plugin-newrelic": "^0.2.4",
|
||||
"@backstage/plugin-pagerduty": "0.2.7",
|
||||
"@backstage/plugin-register-component": "^0.2.8",
|
||||
"@backstage/plugin-rollbar": "^0.2.9",
|
||||
"@backstage/plugin-scaffolder": "^0.4.2",
|
||||
"@backstage/plugin-sentry": "^0.3.4",
|
||||
"@backstage/plugin-search": "^0.2.7",
|
||||
"@backstage/plugin-tech-radar": "^0.3.4",
|
||||
"@backstage/plugin-techdocs": "^0.5.5",
|
||||
"@backstage/plugin-user-settings": "^0.2.5",
|
||||
"@backstage/plugin-welcome": "^0.2.5",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
|
||||
+15
-14
@@ -15,30 +15,30 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
createApp,
|
||||
AlertDisplay,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
createApp,
|
||||
createRouteRef,
|
||||
FlatRoutes,
|
||||
OAuthRequestDialog,
|
||||
SignInPage,
|
||||
} from '@backstage/core';
|
||||
import React from 'react';
|
||||
import Root from './components/Root';
|
||||
import * as plugins from './plugins';
|
||||
import { apis } from './apis';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { providers } from './identityProviders';
|
||||
import { Router as CatalogRouter } from '@backstage/plugin-catalog';
|
||||
import { Router as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import';
|
||||
import { ExplorePage } from '@backstage/plugin-explore';
|
||||
import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql';
|
||||
import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar';
|
||||
import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse';
|
||||
import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component';
|
||||
import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar';
|
||||
import { Router as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Router as SettingsRouter } from '@backstage/plugin-user-settings';
|
||||
import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import';
|
||||
import { Route, Navigate } from 'react-router';
|
||||
|
||||
import React from 'react';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { Navigate, Route } from 'react-router';
|
||||
import { apis } from './apis';
|
||||
import { EntityPage } from './components/catalog/EntityPage';
|
||||
import Root from './components/Root';
|
||||
import { providers } from './identityProviders';
|
||||
import * as plugins from './plugins';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
@@ -78,6 +78,7 @@ const routes = (
|
||||
element={<CatalogRouter EntityPage={EntityPage} />}
|
||||
/>
|
||||
<Route path="/docs" element={<DocsRouter />} />
|
||||
<Route path="/explore" element={<ExplorePage />} />
|
||||
<Route
|
||||
path="/tech-radar"
|
||||
element={<TechRadarRouter width={1500} height={800} />}
|
||||
|
||||
@@ -20,6 +20,7 @@ import HomeIcon from '@material-ui/icons/Home';
|
||||
import ExtensionIcon from '@material-ui/icons/Extension';
|
||||
import RuleIcon from '@material-ui/icons/AssignmentTurnedIn';
|
||||
import MapIcon from '@material-ui/icons/MyLocation';
|
||||
import LayersIcon from '@material-ui/icons/Layers';
|
||||
import LibraryBooks from '@material-ui/icons/LibraryBooks';
|
||||
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
|
||||
import MoneyIcon from '@material-ui/icons/MonetizationOn';
|
||||
@@ -82,6 +83,7 @@ const Root = ({ children }: PropsWithChildren<{}>) => (
|
||||
<SidebarItem icon={HomeIcon} to="/catalog" text="Home" />
|
||||
<SidebarItem icon={ExtensionIcon} to="api-docs" text="APIs" />
|
||||
<SidebarItem icon={LibraryBooks} to="docs" text="Docs" />
|
||||
<SidebarItem icon={LayersIcon} to="explore" text="Explore" />
|
||||
<SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
|
||||
{/* End global nav */}
|
||||
<SidebarDivider />
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ApiEntity,
|
||||
Entity,
|
||||
@@ -64,6 +65,10 @@ import {
|
||||
isPluginApplicableToEntity as isPagerDutyAvailable,
|
||||
PagerDutyCard,
|
||||
} from '@backstage/plugin-pagerduty';
|
||||
import {
|
||||
isRollbarAvailable,
|
||||
Router as RollbarRouter,
|
||||
} from '@backstage/plugin-rollbar';
|
||||
import { Router as SentryRouter } from '@backstage/plugin-sentry';
|
||||
import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs';
|
||||
import { Button, Grid } from '@material-ui/core';
|
||||
@@ -153,6 +158,15 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ErrorsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
switch (true) {
|
||||
case isRollbarAvailable(entity):
|
||||
return <RollbarRouter entity={entity} />;
|
||||
default:
|
||||
return <SentryRouter entity={entity} />;
|
||||
}
|
||||
};
|
||||
|
||||
const ComponentOverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
@@ -212,9 +226,9 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
element={<CICDSwitcher entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/sentry"
|
||||
title="Sentry"
|
||||
element={<SentryRouter entity={entity} />}
|
||||
path="/errors/*"
|
||||
title="Errors"
|
||||
element={<ErrorsSwitcher entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/api/*"
|
||||
@@ -267,9 +281,9 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
element={<LighthouseRouter entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/sentry"
|
||||
title="Sentry"
|
||||
element={<SentryRouter entity={entity} />}
|
||||
path="/errors/*"
|
||||
title="Errors"
|
||||
element={<ErrorsSwitcher entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/docs/*"
|
||||
|
||||
@@ -18,7 +18,7 @@ export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse';
|
||||
export { plugin as CatalogPlugin } from '@backstage/plugin-catalog';
|
||||
export { plugin as ScaffolderPlugin } from '@backstage/plugin-scaffolder';
|
||||
export { plugin as TechRadar } from '@backstage/plugin-tech-radar';
|
||||
export { plugin as Explore } from '@backstage/plugin-explore';
|
||||
export { explorePlugin } from '@backstage/plugin-explore';
|
||||
export { plugin as Circleci } from '@backstage/plugin-circleci';
|
||||
export { plugin as RegisterComponent } from '@backstage/plugin-register-component';
|
||||
export { plugin as Sentry } from '@backstage/plugin-sentry';
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2430ee7c2: Updated the `rootLogger` in `@backstage/backend-common` to support custom logging options. This is useful when you want to make some changes without re-implementing the entire logger and calling `setRootLogger` or `logger.configure`. For example you can add additional `defaultMeta` tags to each log entry. The following changes are included:
|
||||
|
||||
- Added `createRootLogger` which accepts winston `LoggerOptions`. These options allow overriding the default keys.
|
||||
|
||||
Example Usage:
|
||||
|
||||
```ts
|
||||
// Create the logger
|
||||
const logger = createRootLogger({
|
||||
defaultMeta: { appName: 'backstage', appEnv: 'prod' },
|
||||
});
|
||||
|
||||
// Add a custom logger transport
|
||||
logger.add(new MyCustomTransport());
|
||||
|
||||
const config = await loadBackendConfig({
|
||||
argv: process.argv,
|
||||
logger: getRootLogger(), // already set to new logger instance
|
||||
});
|
||||
```
|
||||
|
||||
- Updated dependencies [c4abcdb60]
|
||||
- Updated dependencies [062df71db]
|
||||
- Updated dependencies [064c513e1]
|
||||
- Updated dependencies [e9aab60c7]
|
||||
- Updated dependencies [3149bfe63]
|
||||
- Updated dependencies [2e62aea6f]
|
||||
- @backstage/integration@0.3.2
|
||||
- @backstage/config-loader@0.5.1
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"private": false,
|
||||
@@ -31,8 +31,9 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/config-loader": "^0.5.0",
|
||||
"@backstage/integration": "^0.3.1",
|
||||
"@backstage/config-loader": "^0.5.1",
|
||||
"@backstage/integration": "^0.3.2",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@types/express": "^4.17.6",
|
||||
"archiver": "^5.0.2",
|
||||
@@ -66,7 +67,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/test-utils": "^0.1.5",
|
||||
"@types/archiver": "^5.1.0",
|
||||
"@types/compression": "^1.7.0",
|
||||
|
||||
@@ -63,10 +63,10 @@ export function errorHandler(
|
||||
return (
|
||||
error: Error,
|
||||
_request: Request,
|
||||
response: Response,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
if (response.headersSent) {
|
||||
if (res.headersSent) {
|
||||
// If the headers have already been sent, do not send the response again
|
||||
// as this will throw an error in the backend.
|
||||
next(error);
|
||||
@@ -80,7 +80,9 @@ export function errorHandler(
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
response.status(status).send(message);
|
||||
res.status(status);
|
||||
res.setHeader('content-type', 'text/plain');
|
||||
res.send(message);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
GitHubIntegrationConfig,
|
||||
readGitHubIntegrationConfigs,
|
||||
getGitHubFileFetchUrl,
|
||||
GithubCredentialsProvider,
|
||||
GitHubIntegrationConfig,
|
||||
readGitHubIntegrationConfigs,
|
||||
} from '@backstage/integration';
|
||||
import { RestEndpointMethodTypes } from '@octokit/rest';
|
||||
import fetch from 'cross-fetch';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { Readable } from 'stream';
|
||||
@@ -98,74 +99,26 @@ export class GithubUrlReader implements UrlReader {
|
||||
url: string,
|
||||
options?: ReadTreeOptions,
|
||||
): Promise<ReadTreeResponse> {
|
||||
const { ref, filepath, full_name } = parseGitUrl(url);
|
||||
// Caveat: The ref will totally be incorrect if the branch name includes a /
|
||||
// Thus, readTree can not work on url containing branch name that has a /
|
||||
|
||||
const { headers } = await this.deps.credentialsProvider.getCredentials({
|
||||
url,
|
||||
});
|
||||
|
||||
// Get GitHub API urls for the repository
|
||||
const repoGitHubResponse = await fetch(
|
||||
new URL(`${this.config.apiBaseUrl}/repos/${full_name}`).toString(),
|
||||
{
|
||||
headers,
|
||||
},
|
||||
);
|
||||
if (!repoGitHubResponse.ok) {
|
||||
const message = `Failed to read tree (repository) from ${url}, ${repoGitHubResponse.status} ${repoGitHubResponse.statusText}`;
|
||||
if (repoGitHubResponse.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
const repoResponseJson = await repoGitHubResponse.json();
|
||||
|
||||
// ref is an empty string if no branch is set in provided url to readTree.
|
||||
// Use GitHub API to get the default branch of the repository.
|
||||
const branch = ref || repoResponseJson.default_branch;
|
||||
const branchesApiUrl = repoResponseJson.branches_url;
|
||||
const archiveApiUrl = repoResponseJson.archive_url;
|
||||
|
||||
// Fetch the latest commit in the provided or default branch to compare against
|
||||
// the provided sha.
|
||||
const branchGitHubResponse = await fetch(
|
||||
// branchesApiUrl looks like "https://api.github.com/repos/owner/repo/branches{/branch}"
|
||||
branchesApiUrl.replace('{/branch}', `/${branch}`),
|
||||
{
|
||||
headers,
|
||||
},
|
||||
);
|
||||
if (!branchGitHubResponse.ok) {
|
||||
const message = `Failed to read tree (branch) from ${url}, ${branchGitHubResponse.status} ${branchGitHubResponse.statusText}`;
|
||||
if (branchGitHubResponse.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
const commitSha = (await branchGitHubResponse.json()).commit.sha;
|
||||
const repoDetails = await this.getRepoDetails(url);
|
||||
const commitSha = repoDetails.branch.commit.sha!;
|
||||
|
||||
if (options?.etag && options.etag === commitSha) {
|
||||
throw new NotModifiedError();
|
||||
}
|
||||
|
||||
const archive = await fetch(
|
||||
// archiveApiUrl looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}"
|
||||
archiveApiUrl
|
||||
const { headers } = await this.deps.credentialsProvider.getCredentials({
|
||||
url,
|
||||
});
|
||||
|
||||
// archive_url looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}"
|
||||
const archive = await this.fetchResponse(
|
||||
repoDetails.repo.archive_url
|
||||
.replace('{archive_format}', 'tarball')
|
||||
.replace('{/ref}', `/${commitSha}`),
|
||||
{ headers },
|
||||
);
|
||||
if (!archive.ok) {
|
||||
const message = `Failed to read tree (archive) from ${url}, ${archive.status} ${archive.statusText}`;
|
||||
if (archive.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
const { filepath } = parseGitUrl(url);
|
||||
return await this.deps.treeResponseFactory.fromTarArchive({
|
||||
// TODO(Rugvip): Underlying implementation of fetch will be node-fetch, we probably want
|
||||
// to stick to using that in exclusively backend code.
|
||||
@@ -180,4 +133,59 @@ export class GithubUrlReader implements UrlReader {
|
||||
const { host, token } = this.config;
|
||||
return `github{host=${host},authed=${Boolean(token)}}`;
|
||||
}
|
||||
|
||||
private async getRepoDetails(
|
||||
url: string,
|
||||
): Promise<{
|
||||
repo: RestEndpointMethodTypes['repos']['get']['response']['data'];
|
||||
branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data'];
|
||||
}> {
|
||||
const parsed = parseGitUrl(url);
|
||||
const { ref, full_name } = parsed;
|
||||
|
||||
// Caveat: The ref will totally be incorrect if the branch name includes a
|
||||
// slash. Thus, some operations can not work on URLs containing branch
|
||||
// names that have a slash in them.
|
||||
|
||||
const { headers } = await this.deps.credentialsProvider.getCredentials({
|
||||
url,
|
||||
});
|
||||
|
||||
const repo: RestEndpointMethodTypes['repos']['get']['response']['data'] = await this.fetchJson(
|
||||
`${this.config.apiBaseUrl}/repos/${full_name}`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
// branches_url looks like "https://api.github.com/repos/owner/repo/branches{/branch}"
|
||||
const branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data'] = await this.fetchJson(
|
||||
repo.branches_url.replace('{/branch}', `/${ref || repo.default_branch}`),
|
||||
{ headers },
|
||||
);
|
||||
|
||||
return { repo, branch };
|
||||
}
|
||||
|
||||
private async fetchResponse(
|
||||
url: string | URL,
|
||||
init: RequestInit,
|
||||
): Promise<Response> {
|
||||
const urlAsString = url.toString();
|
||||
|
||||
const response = await fetch(urlAsString, init);
|
||||
|
||||
if (!response.ok) {
|
||||
const message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`;
|
||||
if (response.status === 404) {
|
||||
throw new NotFoundError(message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async fetchJson(url: string | URL, init: RequestInit): Promise<any> {
|
||||
const response = await this.fetchResponse(url, init);
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,11 +71,17 @@ function withRetries(count: number, fn: () => Promise<void>) {
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
if (!error.message.match(/rate limit|Too Many Requests/)) {
|
||||
throw error;
|
||||
} else {
|
||||
console.warn('Request was rate limited', error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('UrlReaders', () => {
|
||||
jest.setTimeout(30_000);
|
||||
|
||||
it(
|
||||
'should read data from azure',
|
||||
withRetries(3, async () => {
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import tar, { Parse, ParseStream, ReadEntry } from 'tar';
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { Readable, pipeline as pipelineCb } from 'stream';
|
||||
import { promisify } from 'util';
|
||||
import concatStream from 'concat-stream';
|
||||
import fs from 'fs-extra';
|
||||
import platformPath from 'path';
|
||||
import { pipeline as pipelineCb, Readable } from 'stream';
|
||||
import tar, { Parse, ParseStream, ReadEntry } from 'tar';
|
||||
import { promisify } from 'util';
|
||||
import {
|
||||
ReadTreeResponse,
|
||||
ReadTreeResponseFile,
|
||||
ReadTreeResponseDirOptions,
|
||||
ReadTreeResponseFile,
|
||||
} from '../types';
|
||||
|
||||
// Tar types for `Parse` is not a proper constructor, but it should be
|
||||
@@ -147,7 +147,7 @@ export class TarArchiveResponse implements ReadTreeResponse {
|
||||
|
||||
const dir =
|
||||
options?.targetDir ??
|
||||
(await fs.mkdtemp(path.join(this.workDir, 'backstage-')));
|
||||
(await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));
|
||||
|
||||
// Equivalent of tar --strip-components=N
|
||||
// When no subPath is given, remove just 1 top level directory
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import unzipper, { Entry } from 'unzipper';
|
||||
import archiver from 'archiver';
|
||||
import fs from 'fs-extra';
|
||||
import platformPath from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import unzipper, { Entry } from 'unzipper';
|
||||
import {
|
||||
ReadTreeResponse,
|
||||
ReadTreeResponseFile,
|
||||
ReadTreeResponseDirOptions,
|
||||
ReadTreeResponseFile,
|
||||
} from '../types';
|
||||
|
||||
// Matches a directory name + one `/` at the start of any string,
|
||||
@@ -144,7 +144,7 @@ export class ZipArchiveResponse implements ReadTreeResponse {
|
||||
|
||||
const dir =
|
||||
options?.targetDir ??
|
||||
(await fs.mkdtemp(path.join(this.workDir, 'backstage-')));
|
||||
(await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));
|
||||
|
||||
await this.stream
|
||||
.pipe(unzipper.Parse())
|
||||
@@ -155,11 +155,11 @@ export class ZipArchiveResponse implements ReadTreeResponse {
|
||||
const entryPath = this.getInnerPath(
|
||||
this.stripTopDirectory(entry.path),
|
||||
);
|
||||
const dirname = path.dirname(entryPath);
|
||||
const dirname = platformPath.dirname(entryPath);
|
||||
if (dirname) {
|
||||
await fs.mkdirp(path.join(dir, dirname));
|
||||
await fs.mkdirp(platformPath.join(dir, dirname));
|
||||
}
|
||||
entry.pipe(fs.createWriteStream(path.join(dir, entryPath)));
|
||||
entry.pipe(fs.createWriteStream(platformPath.join(dir, entryPath)));
|
||||
} else {
|
||||
entry.autodrain();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,32 @@ import { Logger } from 'winston';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ReadTreeResponseFactory } from './tree';
|
||||
|
||||
/**
|
||||
* A generic interface for fetching plain data from URLs.
|
||||
*/
|
||||
export type UrlReader = {
|
||||
read(url: string): Promise<Buffer>;
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
};
|
||||
|
||||
export type UrlReaderPredicateTuple = {
|
||||
predicate: (url: URL) => boolean;
|
||||
reader: UrlReader;
|
||||
};
|
||||
|
||||
/**
|
||||
* A factory function that can read config to construct zero or more
|
||||
* UrlReaders along with a predicate for when it should be used.
|
||||
*/
|
||||
export type ReaderFactory = (options: {
|
||||
config: Config;
|
||||
logger: Logger;
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
}) => UrlReaderPredicateTuple[];
|
||||
|
||||
/**
|
||||
* An options object for readTree operations.
|
||||
*/
|
||||
export type ReadTreeOptions = {
|
||||
/**
|
||||
* A filter that can be used to select which files should be included.
|
||||
@@ -47,39 +73,6 @@ export type ReadTreeOptions = {
|
||||
etag?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A generic interface for fetching plain data from URLs.
|
||||
*/
|
||||
export type UrlReader = {
|
||||
read(url: string): Promise<Buffer>;
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
};
|
||||
|
||||
export type UrlReaderPredicateTuple = {
|
||||
predicate: (url: URL) => boolean;
|
||||
reader: UrlReader;
|
||||
};
|
||||
|
||||
/**
|
||||
* A factory function that can read config to construct zero or more
|
||||
* UrlReaders along with a predicate for when it should be used.
|
||||
*/
|
||||
export type ReaderFactory = (options: {
|
||||
config: Config;
|
||||
logger: Logger;
|
||||
treeResponseFactory: ReadTreeResponseFactory;
|
||||
}) => UrlReaderPredicateTuple[];
|
||||
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
/** The directory to write files to. Defaults to the OS tmpdir or `backend.workingDirectory` if set in config */
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
export type ReadTreeResponse = {
|
||||
/**
|
||||
* files() returns an array of all the files inside the tree and corresponding functions to read their content.
|
||||
@@ -97,3 +90,16 @@ export type ReadTreeResponse = {
|
||||
*/
|
||||
etag: string;
|
||||
};
|
||||
|
||||
export type ReadTreeResponseDirOptions = {
|
||||
/** The directory to write files to. Defaults to the OS tmpdir or `backend.workingDirectory` if set in config */
|
||||
targetDir?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a single file in a readTree response.
|
||||
*/
|
||||
export type ReadTreeResponseFile = {
|
||||
path: string;
|
||||
content(): Promise<Buffer>;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c777df180]
|
||||
- Updated dependencies [2430ee7c2]
|
||||
- Updated dependencies [3149bfe63]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [e44925723]
|
||||
- Updated dependencies [9d6ef14bc]
|
||||
- Updated dependencies [a26668913]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [e9aab60c7]
|
||||
- Updated dependencies [24e47ef1e]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [529d16d27]
|
||||
- Updated dependencies [cdea0baf1]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/plugin-techdocs-backend@0.5.5
|
||||
- @backstage/backend-common@0.5.2
|
||||
- @backstage/plugin-catalog-backend@0.6.0
|
||||
- @backstage/catalog-model@0.7.1
|
||||
- example-app@0.2.14
|
||||
- @backstage/plugin-scaffolder-backend@0.6.0
|
||||
- @backstage/plugin-app-backend@0.3.6
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.13",
|
||||
"version": "0.2.14",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -27,24 +27,24 @@
|
||||
"migrate:create": "knex migrate:make -x ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/plugin-app-backend": "^0.3.5",
|
||||
"@backstage/plugin-app-backend": "^0.3.6",
|
||||
"@backstage/plugin-auth-backend": "^0.2.12",
|
||||
"@backstage/plugin-catalog-backend": "^0.5.5",
|
||||
"@backstage/plugin-catalog-backend": "^0.6.0",
|
||||
"@backstage/plugin-graphql-backend": "^0.1.5",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.6",
|
||||
"@backstage/plugin-kafka-backend": "^0.2.0",
|
||||
"@backstage/plugin-proxy-backend": "^0.2.4",
|
||||
"@backstage/plugin-rollbar-backend": "^0.1.7",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.5.2",
|
||||
"@backstage/plugin-techdocs-backend": "^0.5.4",
|
||||
"@backstage/plugin-scaffolder-backend": "^0.6.0",
|
||||
"@backstage/plugin-techdocs-backend": "^0.5.5",
|
||||
"@gitbeaker/node": "^28.0.2",
|
||||
"@octokit/rest": "^18.0.12",
|
||||
"azure-devops-node-api": "^10.1.1",
|
||||
"dockerode": "^3.2.1",
|
||||
"example-app": "^0.2.13",
|
||||
"example-app": "^0.2.14",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
"knex": "^0.21.6",
|
||||
@@ -54,7 +54,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/dockerode": "^3.2.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-serve-static-core": "^4.17.5"
|
||||
|
||||
@@ -30,6 +30,7 @@ import Docker from 'dockerode';
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
database,
|
||||
}: PluginEnvironment) {
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
const craTemplater = new CreateReactAppTemplater();
|
||||
@@ -54,5 +55,6 @@ export default async function createPlugin({
|
||||
config,
|
||||
dockerClient,
|
||||
entityClient,
|
||||
database,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"cross-fetch": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/jest": "^26.0.7",
|
||||
"msw": "^0.21.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6e612ce25: Adds a new optional `links` metadata field to the Entity class within the `catalog-model` package (as discussed in [[RFC] Entity Links](https://github.com/backstage/backstage/issues/3787)). This PR adds support for the entity links only. Follow up PR's will introduce the UI component to display them.
|
||||
- 025e122c3: Replace `yup` with `ajv`, for validation of catalog entities.
|
||||
- 7881f2117: Introduce json schema variants of the `yup` validation schemas
|
||||
- 11cb5ef94: Implement matchEntityWithRef for client side filtering of entities by ref matching
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -39,7 +39,7 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/lodash": "^4.14.151",
|
||||
|
||||
@@ -27,6 +27,7 @@ export type {
|
||||
} from './Entity';
|
||||
export * from './policies';
|
||||
export {
|
||||
compareEntityToRef,
|
||||
getEntityName,
|
||||
parseEntityName,
|
||||
parseEntityRef,
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
import { ENTITY_DEFAULT_NAMESPACE } from './constants';
|
||||
import { Entity } from './Entity';
|
||||
import { parseEntityName, parseEntityRef, serializeEntityRef } from './ref';
|
||||
import {
|
||||
compareEntityToRef,
|
||||
parseEntityName,
|
||||
parseEntityRef,
|
||||
serializeEntityRef,
|
||||
} from './ref';
|
||||
|
||||
describe('ref', () => {
|
||||
describe('parseEntityName', () => {
|
||||
@@ -381,4 +386,320 @@ describe('ref', () => {
|
||||
).toEqual({ kind: 'a', namespace: 'b', name: 'c/x' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('compareEntityToRef', () => {
|
||||
const entityWithNamespace: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'K',
|
||||
metadata: {
|
||||
name: 'n',
|
||||
namespace: 'ns',
|
||||
},
|
||||
};
|
||||
const entityWithoutNamespace: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'K',
|
||||
metadata: {
|
||||
name: 'n',
|
||||
},
|
||||
};
|
||||
|
||||
it('handles matching string refs', () => {
|
||||
expect(compareEntityToRef(entityWithNamespace, 'K:ns/n')).toBe(true);
|
||||
expect(compareEntityToRef(entityWithNamespace, 'k:nS/N')).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'K:n', {
|
||||
defaultNamespace: 'ns',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'K:n', {
|
||||
defaultNamespace: 'Ns',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'ns/n', { defaultKind: 'K' }),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'n', {
|
||||
defaultKind: 'K',
|
||||
defaultNamespace: 'ns',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'N', {
|
||||
defaultKind: 'k',
|
||||
defaultNamespace: 'nS',
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(compareEntityToRef(entityWithoutNamespace, 'K:deFault/n')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'K:n', {
|
||||
defaultNamespace: 'default',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'K:n', {
|
||||
defaultNamespace: 'deFault',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(compareEntityToRef(entityWithoutNamespace, 'K:n')).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'default/n', {
|
||||
defaultKind: 'K',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'n', {
|
||||
defaultKind: 'K',
|
||||
defaultNamespace: 'default',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'n', {
|
||||
defaultKind: 'K',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('handles mismatching string refs', () => {
|
||||
expect(compareEntityToRef(entityWithNamespace, 'X:ns/n')).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'ns/n', {
|
||||
defaultKind: 'X',
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(compareEntityToRef(entityWithNamespace, 'K:xx/n')).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'K:n', {
|
||||
defaultNamespace: 'xx',
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(compareEntityToRef(entityWithNamespace, 'K:ns/x')).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, 'x', {
|
||||
defaultKind: 'K',
|
||||
defaultNamespace: 'ns',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('handles matching compound refs', () => {
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'ns',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, {
|
||||
kind: 'k',
|
||||
namespace: 'Ns',
|
||||
name: 'N',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithNamespace,
|
||||
{ kind: 'K', name: 'n' },
|
||||
{
|
||||
defaultNamespace: 'ns',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithNamespace,
|
||||
{ namespace: 'ns', name: 'n' },
|
||||
{ defaultKind: 'K' },
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'n', {
|
||||
defaultKind: 'K',
|
||||
defaultNamespace: 'ns',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, 'N', {
|
||||
defaultKind: 'k',
|
||||
defaultNamespace: 'nS',
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'default',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, {
|
||||
kind: 'k',
|
||||
namespace: 'deFault',
|
||||
name: 'N',
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{ kind: 'K', name: 'n' },
|
||||
{
|
||||
defaultNamespace: 'default',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, { kind: 'K', name: 'n' }),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{ namespace: 'default', name: 'n' },
|
||||
{
|
||||
defaultKind: 'K',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{ name: 'n' },
|
||||
{
|
||||
defaultKind: 'K',
|
||||
defaultNamespace: 'default',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{ name: 'N' },
|
||||
{
|
||||
defaultKind: 'k',
|
||||
defaultNamespace: 'defAult',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{ name: 'n' },
|
||||
{
|
||||
defaultKind: 'K',
|
||||
},
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('handles mismatching compound refs', () => {
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, {
|
||||
kind: 'X',
|
||||
namespace: 'ns',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithNamespace,
|
||||
{
|
||||
namespace: 'ns',
|
||||
name: 'n',
|
||||
},
|
||||
{ defaultKind: 'X' },
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, {
|
||||
kind: 'X',
|
||||
namespace: 'default',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{
|
||||
namespace: 'default',
|
||||
name: 'n',
|
||||
},
|
||||
{ defaultKind: 'X' },
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'xx',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithNamespace,
|
||||
{
|
||||
kind: 'K',
|
||||
name: 'n',
|
||||
},
|
||||
{ defaultNamespace: 'xx' },
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'xx',
|
||||
name: 'n',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{
|
||||
kind: 'K',
|
||||
name: 'n',
|
||||
},
|
||||
{ defaultNamespace: 'xx' },
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
compareEntityToRef(entityWithNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'ns',
|
||||
name: 'x',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(entityWithoutNamespace, {
|
||||
kind: 'K',
|
||||
namespace: 'default',
|
||||
name: 'x',
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
compareEntityToRef(
|
||||
entityWithoutNamespace,
|
||||
{
|
||||
kind: 'K',
|
||||
name: 'x',
|
||||
},
|
||||
{ defaultNamespace: 'default' },
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,27 @@ import { EntityName, EntityRef } from '../types';
|
||||
import { ENTITY_DEFAULT_NAMESPACE } from './constants';
|
||||
import { Entity } from './Entity';
|
||||
|
||||
function parseRefString(
|
||||
ref: string,
|
||||
): {
|
||||
kind?: string;
|
||||
namespace?: string;
|
||||
name: string;
|
||||
} {
|
||||
const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim());
|
||||
if (!match) {
|
||||
throw new TypeError(
|
||||
`Entity reference "${ref}" was not on the form [<kind>:][<namespace>/]<name>`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
kind: match[1]?.slice(0, -1),
|
||||
namespace: match[2]?.slice(0, -1),
|
||||
name: match[3],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the kind, namespace and name that form the name triplet of the
|
||||
* given entity.
|
||||
@@ -121,17 +142,11 @@ export function parseEntityRef(
|
||||
}
|
||||
|
||||
if (typeof ref === 'string') {
|
||||
const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim());
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`Entity reference "${ref}" was not on the form [<kind>:][<namespace>/]<name>`,
|
||||
);
|
||||
}
|
||||
|
||||
const parsed = parseRefString(ref);
|
||||
return {
|
||||
kind: match[1]?.slice(0, -1) ?? context.defaultKind,
|
||||
namespace: match[2]?.slice(0, -1) ?? context.defaultNamespace,
|
||||
name: match[3],
|
||||
kind: parsed.kind ?? context.defaultKind,
|
||||
namespace: parsed.namespace ?? context.defaultNamespace,
|
||||
name: parsed.name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,3 +211,53 @@ export function serializeEntityRef(
|
||||
|
||||
return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares an entity to either a string reference or a compound reference.
|
||||
*
|
||||
* The comparison is case insensitive, and all of kind, namespace, and name
|
||||
* must match (after applying the optional context to the ref).
|
||||
*
|
||||
* @param entity The entity to match
|
||||
* @param ref A string or compound entity ref
|
||||
* @param context An optional context of default kind and namespace, that apply
|
||||
* to the ref if given
|
||||
* @returns True if matching, false otherwise
|
||||
*/
|
||||
export function compareEntityToRef(
|
||||
entity: Entity,
|
||||
ref: EntityRef | EntityName,
|
||||
context?: EntityRefContext,
|
||||
): boolean {
|
||||
const entityKind = entity.kind;
|
||||
const entityNamespace = entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE;
|
||||
const entityName = entity.metadata.name;
|
||||
|
||||
let refKind: string | undefined;
|
||||
let refNamespace: string | undefined;
|
||||
let refName: string;
|
||||
if (typeof ref === 'string') {
|
||||
const parsed = parseRefString(ref);
|
||||
refKind = parsed.kind || context?.defaultKind;
|
||||
refNamespace =
|
||||
parsed.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE;
|
||||
refName = parsed.name;
|
||||
} else {
|
||||
refKind = ref.kind || context?.defaultKind;
|
||||
refNamespace =
|
||||
ref.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE;
|
||||
refName = ref.name;
|
||||
}
|
||||
|
||||
if (!refKind || !refNamespace) {
|
||||
throw new Error(
|
||||
`Entity reference or context did not contain kind and namespace`,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
entityKind.toLowerCase() === refKind.toLowerCase() &&
|
||||
entityNamespace.toLowerCase() === refNamespace.toLowerCase() &&
|
||||
entityName.toLowerCase() === refName.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
# @backstage/cli
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 19fe61c27: We have updated the default `eslint` rules in the `@backstage/cli` package.
|
||||
|
||||
```diff
|
||||
-'@typescript-eslint/no-shadow': 'off',
|
||||
-'@typescript-eslint/no-redeclare': 'off',
|
||||
+'no-shadow': 'off',
|
||||
+'no-redeclare': 'off',
|
||||
+'@typescript-eslint/no-shadow': 'error',
|
||||
+'@typescript-eslint/no-redeclare': 'error',
|
||||
```
|
||||
|
||||
The rules are documented [here](https://eslint.org/docs/rules/no-shadow) and [here](https://eslint.org/docs/rules/no-redeclare).
|
||||
|
||||
This involved a large number of small changes to the code base. When you compile your own code using the CLI, you may also be
|
||||
affected. We consider these rules important, and the primary recommendation is to try to update your code according to the
|
||||
documentation above. But those that prefer to not enable the rules, or need time to perform the updates, may update their
|
||||
local `.eslintrc.js` file(s) in the repo root and/or in individual plugins as they see fit:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// ... other declarations
|
||||
rules: {
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Because of the nature of this change, we're unable to provide a grace period for the update :(
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 398e1f83e: Update `create-plugin` template to use the new composability API, by switching to exporting a single routable extension component.
|
||||
- e9aab60c7: Fixed module resolution of external libraries during backend development. Modules used to be resolved relative to the backend entrypoint, but are now resolved relative to each individual module.
|
||||
- a08c4b0b0: Add check for outdated/duplicate packages to yarn start
|
||||
- Updated dependencies [062df71db]
|
||||
- Updated dependencies [e9aab60c7]
|
||||
- @backstage/config-loader@0.5.1
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -38,8 +38,10 @@ module.exports = {
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
|
||||
'no-console': 0, // Permitted in console programs
|
||||
'new-cap': ['error', { capIsNew: false }], // Because Express constructs things e.g. like 'const r = express.Router()'
|
||||
|
||||
@@ -45,8 +45,10 @@ module.exports = {
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
'no-undef': 'off',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-duplicates': 'warn',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/cli",
|
||||
"description": "CLI for developing Backstage plugins and apps",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -30,7 +30,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "^0.1.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/config-loader": "^0.5.0",
|
||||
"@backstage/config-loader": "^0.5.1",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
"@lerna/package-graph": "^3.18.5",
|
||||
"@lerna/project": "^3.18.0",
|
||||
@@ -93,7 +93,7 @@
|
||||
"rollup-plugin-esbuild": "2.6.x",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.2",
|
||||
"rollup-plugin-postcss": "^3.1.1",
|
||||
"rollup-plugin-typescript2": "^0.27.3",
|
||||
"rollup-plugin-typescript2": "^0.29.0",
|
||||
"rollup-pluginutils": "^2.8.2",
|
||||
"semver": "^7.3.2",
|
||||
"start-server-webpack-plugin": "^2.2.5",
|
||||
@@ -113,12 +113,12 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@types/diff": "^4.0.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user