diff --git a/.changeset/bright-moons-open.md b/.changeset/bright-moons-open.md new file mode 100644 index 0000000000..2668dfb2e6 --- /dev/null +++ b/.changeset/bright-moons-open.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-react': patch +'@backstage/plugin-search': patch +--- + +Fixes the search component not registering the first search on navigate to the search page. diff --git a/.changeset/cli-common-cached-paths.md b/.changeset/cli-common-cached-paths.md new file mode 100644 index 0000000000..6d9ec14297 --- /dev/null +++ b/.changeset/cli-common-cached-paths.md @@ -0,0 +1,28 @@ +--- +'@backstage/cli-common': minor +--- + +Added `targetPaths` and `findOwnPaths` as replacements for `findPaths`, with a cleaner separation between target project paths and package-relative paths. + +To migrate existing `findPaths` usage: + +```ts +// Before +import { findPaths } from '@backstage/cli-common'; +const paths = findPaths(__dirname); + +// After — for target project paths (cwd-based): +import { targetPaths } from '@backstage/cli-common'; +// paths.targetDir → targetPaths.dir +// paths.targetRoot → targetPaths.rootDir +// paths.resolveTarget('src') → targetPaths.resolve('src') +// paths.resolveTargetRoot('yarn.lock') → targetPaths.resolveRoot('yarn.lock') + +// After — for package-relative paths: +import { findOwnPaths } from '@backstage/cli-common'; +const own = findOwnPaths(__dirname); +// paths.ownDir → own.dir +// paths.ownRoot → own.rootDir +// paths.resolveOwn('config/jest.js') → own.resolve('config/jest.js') +// paths.resolveOwnRoot('tsconfig.json') → own.resolveRoot('tsconfig.json') +``` diff --git a/.changeset/cli-internal-refactor.md b/.changeset/cli-internal-refactor.md index 97957a2cd2..c3f8f38540 100644 --- a/.changeset/cli-internal-refactor.md +++ b/.changeset/cli-internal-refactor.md @@ -2,4 +2,4 @@ '@backstage/cli': patch --- -Internal refactor to improve module independence. +Internal refactor to use new concurrency utilities from `@backstage/cli-node`. diff --git a/.changeset/cli-node-parallel-helpers.md b/.changeset/cli-node-parallel-helpers.md new file mode 100644 index 0000000000..5ad7ad7f4d --- /dev/null +++ b/.changeset/cli-node-parallel-helpers.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Added `runConcurrentTasks` and `runWorkerQueueThreads` utilities, moved from the `@backstage/cli` internal code. diff --git a/.changeset/cli-translations-export-import.md b/.changeset/cli-translations-export-import.md new file mode 100644 index 0000000000..6631eebdfd --- /dev/null +++ b/.changeset/cli-translations-export-import.md @@ -0,0 +1,9 @@ +--- +'@backstage/cli': patch +--- + +Added `translations export` and `translations import` commands for managing translation files. + +The `translations export` command discovers all `TranslationRef` definitions across frontend plugin dependencies and exports their default messages as JSON files. The `translations import` command generates `TranslationResource` wiring code from translated JSON files, ready to be plugged into the app. + +Both commands support a `--pattern` option for controlling the message file layout, for example `--pattern '{lang}/{id}.json'` for language-based directory grouping. diff --git a/.changeset/fix-prettier-existence-check.md b/.changeset/fix-prettier-existence-check.md new file mode 100644 index 0000000000..96e8b79082 --- /dev/null +++ b/.changeset/fix-prettier-existence-check.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Fixed prettier existence checks in OpenAPI commands to use `fs.pathExists` instead of checking the resolved path string, which was always truthy. diff --git a/.changeset/mean-fans-decide.md b/.changeset/mean-fans-decide.md new file mode 100644 index 0000000000..5fe04beb40 --- /dev/null +++ b/.changeset/mean-fans-decide.md @@ -0,0 +1,7 @@ +--- +'@backstage/ui': patch +--- + +Fixed focus-visible outline styles for Menu and Select components. + +**Affected components:** Menu, Select diff --git a/.changeset/metal-humans-move.md b/.changeset/metal-humans-move.md new file mode 100644 index 0000000000..21881246fc --- /dev/null +++ b/.changeset/metal-humans-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Minor internal optimisation diff --git a/.changeset/migrate-to-target-paths.md b/.changeset/migrate-to-target-paths.md new file mode 100644 index 0000000000..efc03ba289 --- /dev/null +++ b/.changeset/migrate-to-target-paths.md @@ -0,0 +1,12 @@ +--- +'@backstage/cli': patch +'@backstage/cli-node': patch +'@backstage/backend-dynamic-feature-service': patch +'@backstage/codemods': patch +'@backstage/config-loader': patch +'@backstage/create-app': patch +'@backstage/repo-tools': patch +'@techdocs/cli': patch +--- + +Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. diff --git a/.changeset/ninety-corners-flash.md b/.changeset/ninety-corners-flash.md new file mode 100644 index 0000000000..f858ec0593 --- /dev/null +++ b/.changeset/ninety-corners-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Migrates existing catalog metrics to use the alpha MetricsService. This release is a 1:1 migration with no breaking changes. diff --git a/.changeset/orange-mugs-post-1.md b/.changeset/orange-mugs-post-1.md new file mode 100644 index 0000000000..bbf2b51082 --- /dev/null +++ b/.changeset/orange-mugs-post-1.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Added opentelemetry metrics for SCM events: + +- `catalog.events.scm.messages` with attribute `eventType`: Counter for the number of SCM events actually received by the catalog backend. The `eventType` is currently either `location` or `repository`. diff --git a/.changeset/orange-mugs-post-2.md b/.changeset/orange-mugs-post-2.md new file mode 100644 index 0000000000..ed78bbc175 --- /dev/null +++ b/.changeset/orange-mugs-post-2.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-node': minor +--- + +Added the ability for SCM events subscribers to mark the fact that they have taken actions based on events, which produces output metrics: + +- `catalog.events.scm.actions` with attribute `action`: Counter for the number of actions actually taken by catalog internals or other subscribers, based on SCM events. The `action` is currently either `create`, `delete`, `refresh`, or `move`. diff --git a/.changeset/pre.json b/.changeset/pre.json index 00dbb0f757..7113b1ee96 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -210,5 +210,43 @@ "@backstage/plugin-user-settings-backend": "0.4.0", "@backstage/plugin-user-settings-common": "0.1.0" }, - "changesets": [] + "changesets": [ + "add-masked-and-hidden-option", + "blue-moons-crash", + "bright-moons-open", + "brown-towns-find", + "bump-bfj-v9", + "cli-common-cached-paths", + "cli-internal-refactor", + "cli-node-parallel-helpers", + "cli-translations-export-import", + "dependabot-d2ec7e9", + "fancy-ends-turn", + "fix-frontend-feature-compat", + "fix-prettier-existence-check", + "fluffy-owls-act", + "long-hairs-throw", + "mean-fans-decide", + "metal-humans-move", + "migrate-to-target-paths", + "ninety-corners-flash", + "orange-mugs-post-1", + "orange-mugs-post-2", + "pink-terms-know", + "polite-singers-lead", + "pretty-days-taste", + "rare-adults-attack", + "renovate-8b1c21e", + "rude-groups-shout", + "scaffolder-export-form-fields-api", + "silver-pigs-remain", + "sixty-pianos-begin", + "stable-translation-plugin-app", + "stable-translation-test-utils", + "stupid-pans-hope", + "swift-flowers-grin", + "swift-ravens-jog", + "tired-bushes-write", + "twenty-worlds-create" + ] } diff --git a/.changeset/rare-adults-attack.md b/.changeset/rare-adults-attack.md new file mode 100644 index 0000000000..8117f26dea --- /dev/null +++ b/.changeset/rare-adults-attack.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-defaults': patch +--- + +Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins. diff --git a/.changeset/rude-groups-shout.md b/.changeset/rude-groups-shout.md new file mode 100644 index 0000000000..59e4a22aa9 --- /dev/null +++ b/.changeset/rude-groups-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Improved type safety in `useDefinition` by centralizing prop resolution and strengthening the `BgPropsConstraint` to require that `bg` provider components declare `children` as a required prop in their OwnProps type. diff --git a/.changeset/scaffolder-export-form-fields-api.md b/.changeset/scaffolder-export-form-fields-api.md new file mode 100644 index 0000000000..02ead2d2b2 --- /dev/null +++ b/.changeset/scaffolder-export-form-fields-api.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Added back the `formFieldsApiRef` and `ScaffolderFormFieldsApi` alpha exports that were unintentionally removed. diff --git a/.changeset/silver-pigs-remain.md b/.changeset/silver-pigs-remain.md new file mode 100644 index 0000000000..d6481f2990 --- /dev/null +++ b/.changeset/silver-pigs-remain.md @@ -0,0 +1,7 @@ +--- +'@backstage/ui': patch +--- + +Added proper cursor styles for RadioGroup items. + +**Affected components:** RadioGroup diff --git a/.changeset/sixty-pianos-begin.md b/.changeset/sixty-pianos-begin.md new file mode 100644 index 0000000000..98db19c21d --- /dev/null +++ b/.changeset/sixty-pianos-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` diff --git a/.changeset/stable-translation-plugin-app.md b/.changeset/stable-translation-plugin-app.md new file mode 100644 index 0000000000..6e57cfeeb8 --- /dev/null +++ b/.changeset/stable-translation-plugin-app.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app': patch +--- + +Switched translation API imports (`translationApiRef`, `appLanguageApiRef`) from the alpha `@backstage/core-plugin-api/alpha` path to the stable `@backstage/frontend-plugin-api` export. This has no effect on runtime behavior. diff --git a/.changeset/stable-translation-test-utils.md b/.changeset/stable-translation-test-utils.md new file mode 100644 index 0000000000..3d624a5dc8 --- /dev/null +++ b/.changeset/stable-translation-test-utils.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-test-utils': patch +--- + +Switched `MockTranslationApi` and related test utility imports from `@backstage/core-plugin-api/alpha` to the stable `@backstage/frontend-plugin-api` export. The `TranslationApi` type in the API report is now sourced from a single package. This has no effect on runtime behavior. diff --git a/.changeset/stupid-pans-hope.md b/.changeset/stupid-pans-hope.md new file mode 100644 index 0000000000..4fd8c5914a --- /dev/null +++ b/.changeset/stupid-pans-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +Minor update to catalog client docs diff --git a/.changeset/swift-ravens-jog.md b/.changeset/swift-ravens-jog.md new file mode 100644 index 0000000000..db92764560 --- /dev/null +++ b/.changeset/swift-ravens-jog.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-mcp-actions-backend': patch +--- + +Adds two new metrics to track MCP server operations and sessions. + +- `mcp.server.operation.duration`: The duration taken to process an individual MCP operation +- `mcp.server.session.duration`: The duration of the MCP session from the perspective of the server diff --git a/.changeset/tired-bushes-write.md b/.changeset/tired-bushes-write.md new file mode 100644 index 0000000000..af49530ef4 --- /dev/null +++ b/.changeset/tired-bushes-write.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Update migrations to be reversible diff --git a/.changeset/twenty-worlds-create.md b/.changeset/twenty-worlds-create.md new file mode 100644 index 0000000000..e7e4770938 --- /dev/null +++ b/.changeset/twenty-worlds-create.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Adds a new metrics service mock to be leveraged in tests diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md deleted file mode 100644 index 170a4eb868..0000000000 --- a/.claude/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -Follow the instructions at /.github/copilot-instructions.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 120000 index 0000000000..be77ac83a1 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1 @@ +../AGENTS.md \ No newline at end of file diff --git a/.cursor/rules/general.mdc b/.cursor/rules/general.mdc deleted file mode 100644 index 3a81a0cb5f..0000000000 --- a/.cursor/rules/general.mdc +++ /dev/null @@ -1,7 +0,0 @@ ---- -description: General project guidelines for Backstage development -globs: -alwaysApply: true ---- - -Follow the instructions at /.github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2157025b7b..9ded15067a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,49 +1,3 @@ -Backstage is an open platform for building developer portals. This is a TypeScript monorepo using Yarn workspaces. - -## Key Directories - -- `/packages`: Core framework packages (prefixed `@backstage/`) -- `/plugins`: Plugin packages (prefixed `@backstage/plugin-*`) -- `/packages/app` and `/packages/backend`: Example app for local development -- `/packages/app`: Main example app using the new frontend system -- `/packages/app-legacy`: Example app using the old frontend system -- `/docs`: Documentation files - -Packages prefixed with `core-` (e.g., `@backstage/core-plugin-api`) are part of the old frontend system. Packages prefixed with `frontend-` (e.g., `@backstage/frontend-plugin-api`) are part of the new frontend system (NFS). Packages prefixed with `backend-` (e.g., `@backstage/backend-plugin-api`) are part of the backend system. - -## Code Standards - -The following files contain guidelines for the project: - -- `/CONTRIBUTING.md`: comprehensive contribution guidelines. -- `/STYLE.md`: guidelines for code style. -- `/REVIEWING.md`: guidelines for pull requests and writing changesets. -- `/SECURITY.md`: guidelines for security. -- `/docs/architecture-decisions/`: contains the architecture decisions for the project. - -## Development Flow - -Before any of these commands can be run, you need to run `yarn install` in the project root. - -- Build: There is no need to build the project during development, and it is verified automatically in the CI pipeline. -- Test: Use `yarn test --no-watch ` in the project root to run tests. The path can be either a single file or a directory. Always provide a path, avoid running all tests. -- Type checking: Use `yarn tsc` in the project root to run the type checker. -- Code formatting: Use `yarn prettier --write ` to format code. -- Lint: Use `yarn lint --fix` in the project root to run the linter. -- API reports: Before submitting a pull request with changes to any package in the workspace, run `yarn build:api-reports` in the project root to generate API reports for all packages. -- Dev server: Use `yarn start` to run the example app locally (frontend on :3000, backend on :7007). -- Create: Use `yarn new` to scaffold new plugins, packages, or modules. - -You MUST NOT create a release by running `yarn changesets version` or `yarn release` as part of any changes. Releases are created by separate workflows. - -All changes that affect the published version of packages in the `/packages` and `/plugins` directories must be accompanied by a changeset. Only non-private packages require changesets. See the guidelines in `/CONTRIBUTING.md#creating-changesets` for information on how to write good changesets. Changesets are stored in the `/.changeset` directory. Breaking changes must be accompanied by a `minor` version bump for packages below version `1.0.0`, or a `major` version bump for packages at version `1.0.0` or higher. - -Never update ESLint, Prettier, or TypeScript configuration files unless specifically requested. - -## Repository Structure - -See `/docs/contribute/project-structure.md` for a detailed description of the repository structure. - ## Pull Request Reviews When reviewing a pull request you MUST calculate a priority score between 0 and 100, where a higher score indicates higher priority. You MUST include the score as an HTML comment at the very beginning of the "PR Overview" section, using the following format: ``. diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 2c4b234fb2..f6f37b17cf 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -322,6 +322,7 @@ openapi OpenSearch OpenShift openssl +opentelemetry orgs overridable padding diff --git a/.patches/pr-32903.txt b/.patches/pr-32903.txt deleted file mode 100644 index a61501edbe..0000000000 --- a/.patches/pr-32903.txt +++ /dev/null @@ -1 +0,0 @@ -Add missing sharing extensions sidebar item in frontend system architecture docs \ No newline at end of file diff --git a/.patches/pr-32905.txt b/.patches/pr-32905.txt deleted file mode 100644 index 3af61baa35..0000000000 --- a/.patches/pr-32905.txt +++ /dev/null @@ -1 +0,0 @@ -Fix type compatibility for older plugins in FrontendFeature type \ No newline at end of file diff --git a/.patches/pr-32973.txt b/.patches/pr-32973.txt new file mode 100644 index 0000000000..6d83c5d66d --- /dev/null +++ b/.patches/pr-32973.txt @@ -0,0 +1 @@ +Fixes the search component to register the first search that happens on initial navigation to the search page. \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..001989d9b6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,53 @@ +Backstage is an open platform for building developer portals. This is a TypeScript monorepo using Yarn workspaces. + +## Key Directories + +- `/packages`: Core framework packages (prefixed `@backstage/`) +- `/plugins`: Plugin packages (prefixed `@backstage/plugin-*`) +- `/packages/app` and `/packages/backend`: Example app for local development +- `/packages/app`: Main example app using the new frontend system +- `/packages/app-legacy`: Example app using the old frontend system +- `/docs`: Documentation files + +Packages prefixed with `core-` (e.g., `@backstage/core-plugin-api`) are part of the old frontend system. Packages prefixed with `frontend-` (e.g., `@backstage/frontend-plugin-api`) are part of the new frontend system (NFS). Packages prefixed with `backend-` (e.g., `@backstage/backend-plugin-api`) are part of the backend system. + +## Code Standards + +The following files contain guidelines for the project: + +- `/CONTRIBUTING.md`: comprehensive contribution guidelines. +- `/STYLE.md`: guidelines for code style. +- `/REVIEWING.md`: guidelines for pull requests and writing changesets. +- `/SECURITY.md`: guidelines for security. +- `/docs/architecture-decisions/`: contains the architecture decisions for the project. + +When writing or generating code, always match the existing coding style of each individual package and file. Different packages in the monorepo may have different conventions — consistency within a package is more important than consistency across the repo. + +When writing or generating tests, prefer fewer thorough tests with multiple assertions over many small tests. When using React Testing Library, prefer using `screen` and `.findBy*` queries over `waitFor`, and avoid adding test IDs to the implementation. + +## Development Flow + +Before any of these commands can be run, you need to run `yarn install` in the project root. + +- Build: There is no need to build the project during development, and it is verified automatically in the CI pipeline. +- Test: Use `CI=1 yarn test ` in the project root to run tests. The path can be either a single file or a directory. Always provide a path, avoid running all tests. +- Type checking: Use `yarn tsc` in the project root to run the type checker. Do not try to run it somewhere else than the project root and do not supply any options. +- Code formatting: Use `yarn prettier --write <...paths>` to format code. Run it explicitly for file paths that you know are changed, not for entire folders - otherwise it may change formatting of unrelated files. +- Lint: Use `yarn lint --fix` in the project root to run the linter. +- API reports: Before submitting a pull request with changes to any package in the workspace, run `yarn build:api-reports` in the project root to generate API reports for all packages. +- Dev server: Use `yarn start` to run the example app locally (frontend on :3000, backend on :7007). +- Create: Use `yarn new` to scaffold new plugins, packages, or modules. + +You MUST NOT run builds or create a release by running `yarn build`, `yarn changesets version`, or `yarn release` as part of any changes. Builds and releases are made by separate workflows. + +All changes that affect the published version of packages in the `/packages` and `/plugins` directories must be accompanied by a changeset. Only non-private packages require changesets. See the guidelines in `/CONTRIBUTING.md#creating-changesets` for information on how to write good changesets. Changesets are stored in the `/.changeset` directory and should be created by writing changeset files directly — never use the changeset CLI. Breaking changes must be accompanied by a `minor` version bump for packages below version `1.0.0`, or a `major` version bump for packages at version `1.0.0` or higher. For non-breaking changes that introduce new APIs or features, use `minor` for packages at version `1.0.0` or higher, and `patch` for packages below `1.0.0`. Each changeset message should be relevant to the specific package it targets and written for Backstage adopters as the audience — avoid referencing internal implementation details. If a change spans multiple packages you often need to create separate changesets to make sure they are tailored to each package. + +When creating pull requests, use the template at `/.github/PULL_REQUEST_TEMPLATE.md`. + +Never update ESLint, Prettier, or TypeScript configuration files unless specifically requested. + +Never make changes to the release notes in `/docs/releases` unless explicitly asked. These document past releases and should not be updated based on newer changes. + +## Repository Structure + +See `/docs/contribute/project-structure.md` for a detailed description of the repository structure. diff --git a/beps/0012-metrics-service/README.md b/beps/0012-metrics-service/README.md index 59096d11d8..87b2059f02 100644 --- a/beps/0012-metrics-service/README.md +++ b/beps/0012-metrics-service/README.md @@ -23,7 +23,6 @@ creation-date: 2025-06-23 - [Integration with OpenTelemetry Auto-Instrumentation](#integration-with-opentelemetry-auto-instrumentation) - [Configuration](#configuration) - [Interface](#interface) - - [Root Metrics Service](#root-metrics-service) - [Plugin Metrics Service](#plugin-metrics-service) - [Example](#example) - [Release Plan](#release-plan) @@ -36,7 +35,7 @@ Add a core `MetricsService` to Backstage's framework to provide a unified interf ## Motivation -While individual plugins may implement their own metrics, there's no standardized approach leading to inconsistent metrics patterns across the ecosystem. For example, both `catalog_entities_count` and `catalog.processed.entities.count` are examples of existing metric patterns. Ideally, these would be standardized to `backstage.plugin.catalog.entities.count` and `backstage.plugin.catalog.entities.processed.total` respectively. +While individual plugins may implement their own metrics, there's no standardized approach leading to inconsistent metrics patterns across the ecosystem and incompatibility with OpenTelemetry semantic conventions. For example, a plugin implementing MCP functionality might incorrectly namespace metrics as `backstage_mcp_client_duration` when OpenTelemetry semantic conventions explicitly define `mcp.client.operation.duration` as the standard. By providing a core metrics service: @@ -45,7 +44,7 @@ By providing a core metrics service: ### Goals -- Plugin-scoped metric namespacing +- Plugin identification via OpenTelemetry Instrumentation Scope - Consistent metrics patterns across all plugins - Aligned with OpenTelemetry industry standards - Provide a familiar interface as other core services @@ -124,9 +123,12 @@ The `MetricsService` **complements** rather than duplicates auto-instrumentation // MetricsService provides (manually): const entityMetrics = metricsService.createCounter('entities.processed.total'); -entityMetrics.add(entities.length, { operation: 'refresh', kind: 'Component' }); +entityMetrics.add(entities.length, { + operation: 'refresh', + 'entity.kind': 'Component', +}); -// Metric is now available as `backstage.plugin.catalog.entities.processed.total` +// Metric is now available as `entities.processed.total` ``` ### Configuration @@ -162,43 +164,21 @@ interface MetricsService { } ``` -#### Root Metrics Service - -The `RootMetricsService` is responsible for providing metrics to other root services and creating both plugin-scoped and core-scoped `MetricsService` instances. - -```ts -interface RootMetricsService { - // note: no config is provided to the root service. - static forRoot(): RootMetricsService; - forPlugin(pluginId: string): MetricsService; - - // final implementation will be similar to - forService(serviceName: string, scope: 'plugin' | 'core'): MetricsService; -} - -export const rootMetricsServiceFactory = createServiceFactory({ - // depends on as little as possible so that it can be initialized as early as possible. - service: rootMetricsServiceRef, - deps: {}, - factory: () => { - return DefaultRootMetricsService.forRoot(); - }, -}); -``` - #### Plugin Metrics Service -Each plugin receives a metrics service that automatically namespaces all metrics to match the naming conventions. +Each plugin receives a metrics service that automatically configures the Instrumentation Scope to identify the plugin. The scope name follows the pattern `backstage-plugin-{pluginId}`. ```ts -const metricsServiceFactory = createServiceFactory({ - service: metricsServiceRef, +export const metricsServiceFactory = createServiceFactory({ + service: coreServices.metrics, deps: { - rootMetrics: coreServices.rootMetrics, pluginMetadata: coreServices.pluginMetadata, }, - factory: ({ rootMetrics, pluginMetadata }) => { - return rootMetrics.forPlugin(pluginMetadata.getId()); + factory: ({ pluginMetadata }) => { + const pluginId = pluginMetadata.getId(); + const scopeName = `backstage-plugin-${pluginId}`; + + return new DefaultMetricsService(scopeName, version, ...); }, }); ``` @@ -248,3 +228,22 @@ entitiesProcessed.add(100); - Plugin authors continue to implement their own metrics as they see fit. - A combined TelemetryService that provides both metrics and tracing. + +### Rejected: Forced Namespace Prefixes + +Prepend `backstage.plugin.{pluginId}.` to all metric names. This was the original proposal but conflicts with OpenTelemetry semantic conventions. + +**Problems:** + +- Makes it impossible to use standard semantic conventions like `mcp.*`, `gen_ai.*`, `http.*` +- Breaks compatibility with industry-standard observability tooling +- Prevents cross-service metric aggregation +- Goes against OpenTelemetry best practices and official guidance + +**Example of conflict:** + +```ts +// Plugin wants to emit: mcp.client.operation.duration +// Framework forces: backstage.plugin.mcp-actions.mcp.client.operation.duration +// This violates the semantic convention and breaks tooling +``` diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 4eb5e864d1..2770f76799 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -1,12 +1,12 @@ --- id: internationalization -title: Internationalization (Experimental) -description: Documentation on adding internationalization to the plugin +title: Internationalization +description: Documentation on adding internationalization to plugins and apps --- ## Overview -The Backstage core function provides internationalization for plugins. The underlying library is [`i18next`](https://www.i18next.com/) with some additional Backstage typescript magic for type safety with keys. +The Backstage core function provides internationalization for plugins and apps. The underlying library is [`i18next`](https://www.i18next.com/) with some additional Backstage typescript magic for type safety with keys. ## For a plugin developer @@ -183,16 +183,56 @@ return ( The return type of the outer `t` function will be a `JSX.Element`, with the underlying value being a React fragment of the different parts of the message. -## For an application developer overwrite plugin messages +## For an application developer -Step 1: Create translation resources +As an app developer you can both override the default English messages of any plugin, and provide translations for additional languages. -You should separate different translations to their own files and import them in the main file: +### Overriding messages + +To customize specific messages without adding new languages, create a translation resource that overrides the default English messages: + +```ts +// packages/app/src/translations/catalog.ts + +import { createTranslationResource } from '@backstage/frontend-plugin-api'; +import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + +export const catalogTranslations = createTranslationResource({ + ref: catalogTranslationRef, + translations: { + en: () => + Promise.resolve({ + default: { + 'indexPage.title': 'Service directory', + 'indexPage.createButtonTitle': 'Register new service', + }, + }), + }, +}); +``` + +Then register it in your app: + +```diff ++ import { catalogTranslations } from './translations/catalog'; + + const app = createApp({ ++ __experimentalTranslations: { ++ resources: [catalogTranslations], ++ }, + }) +``` + +You only need to include the keys you want to override — any missing keys fall back to the plugin's defaults. + +### Adding language translations + +To add support for additional languages, create translation resources with lazy-loaded message files for each language: ```ts // packages/app/src/translations/userSettings.ts -import { createTranslationResource } from '@backstage/core-plugin-api/alpha'; +import { createTranslationResource } from '@backstage/frontend-plugin-api'; import { userSettingsTranslationRef } from '@backstage/plugin-user-settings/alpha'; export const userSettingsTranslations = createTranslationResource({ @@ -203,10 +243,12 @@ export const userSettingsTranslations = createTranslationResource({ }); ``` +The translation messages can be defined using `createTranslationMessages` for type safety: + ```ts // packages/app/src/translations/userSettings-zh.ts -import { createTranslationMessages } from '@backstage/core-plugin-api/alpha'; +import { createTranslationMessages } from '@backstage/frontend-plugin-api'; import { userSettingsTranslationRef } from '@backstage/plugin-user-settings/alpha'; const zh = createTranslationMessages({ @@ -221,7 +263,7 @@ const zh = createTranslationMessages({ export default zh; ``` -It's also possible to export the list of messages directly: +Or as a plain object export: ```ts // packages/app/src/translations/userSettings-zh.ts @@ -239,11 +281,7 @@ export default { }; ``` -You should change `zh` under the translations object to your local language. - -Step 2: Config translations in `packages/app/src/App.tsx` - -In an app you can both override the default messages, as well as register translations for additional languages: +Register it with the available languages declared: ```diff + import { userSettingsTranslations } from './translations/userSettings'; @@ -256,6 +294,116 @@ In an app you can both override the default messages, as well as register transl }) ``` -Step 3: Check everything is working correctly +Go to the Settings page — you should see language switching buttons. Switch languages to verify your translations are loaded correctly. -Go to `Settings` page, you should see change language buttons just under change theme buttons. And then switch language, you should see language had changed +### Using the CLI for full translation workflows + +When translating your app to other languages at scale — especially when working with external translation systems — the Backstage CLI provides `translations export` and `translations import` commands that automate the extraction and wiring of translation messages across all your plugin dependencies. + +#### Exporting default messages + +From your app package directory (e.g. `packages/app`), run: + +```bash +yarn backstage-cli translations export +``` + +This scans all frontend plugin dependencies (including transitive ones) for `TranslationRef` definitions and writes their default English messages as JSON files: + +```text +translations/ + manifest.json + messages/ + catalog.en.json + org.en.json + scaffolder.en.json + ... +``` + +Each `.en.json` file contains the flattened message keys and their default values: + +```json +{ + "indexPage.title": "All your components", + "indexPage.createButtonTitle": "Create new component", + "entityPage.notFound": "Entity not found" +} +``` + +#### Creating translations + +Copy the exported files and translate them for your target languages: + +```bash +cp translations/messages/catalog.en.json translations/messages/catalog.zh.json +``` + +Then edit `catalog.zh.json` with the translated strings. You only need to include the keys you want to translate — missing keys fall back to the English defaults at runtime. + +#### Generating wiring code + +Once you have translated files in place, run: + +```bash +yarn backstage-cli translations import +``` + +This generates a TypeScript module at `src/translations/resources.ts` that wires everything together: + +```ts +// This file is auto-generated by backstage-cli translations import +// Do not edit manually. + +import { createTranslationResource } from '@backstage/frontend-plugin-api'; +import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + +export default [ + createTranslationResource({ + ref: catalogTranslationRef, + translations: { + zh: () => import('../../translations/messages/catalog.zh.json'), + }, + }), +]; +``` + +Import the generated resources in your app: + +```ts +import translationResources from './translations/resources'; + +const app = createApp({ + __experimentalTranslations: { + availableLanguages: ['en', 'zh'], + resources: translationResources, + }, +}); +``` + +#### Custom file patterns + +By default, message files use the pattern `messages/{id}.{lang}.json` (e.g. `messages/catalog.en.json`). You can change this with the `--pattern` option: + +```bash +yarn backstage-cli translations export --pattern '{lang}/{id}.json' +``` + +This produces a directory structure grouped by language instead: + +```text +translations/en/catalog.json +translations/zh/catalog.json +``` + +The pattern is stored in the manifest, so the `import` command automatically uses the same layout. + +#### Integration with external translation systems + +The exported JSON files are standard key-value pairs compatible with most external translation systems. A typical workflow looks like: + +1. Run `translations export` to generate the source English files +2. Upload the `.en.json` files to your translation system +3. Download the translated files back into the translations directory +4. Run `translations import` to regenerate the wiring code + +For full command reference, see the [CLI commands documentation](../tooling/cli/03-commands.md#translations-export). diff --git a/docs/releases/v1.49.0-next.0-changelog.md b/docs/releases/v1.49.0-next.0-changelog.md new file mode 100644 index 0000000000..fcfc092d5e --- /dev/null +++ b/docs/releases/v1.49.0-next.0-changelog.md @@ -0,0 +1,2362 @@ +# Release v1.49.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.49.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.49.0-next.0) + +## @backstage/cli-common@0.2.0-next.0 + +### Minor Changes + +- 56bd494: Added `targetPaths` and `findOwnPaths` as replacements for `findPaths`, with a cleaner separation between target project paths and package-relative paths. + + To migrate existing `findPaths` usage: + + ```ts + // Before + import { findPaths } from '@backstage/cli-common'; + const paths = findPaths(__dirname); + + // After — for target project paths (cwd-based): + import { targetPaths } from '@backstage/cli-common'; + // paths.targetDir → targetPaths.dir + // paths.targetRoot → targetPaths.rootDir + // paths.resolveTarget('src') → targetPaths.resolve('src') + // paths.resolveTargetRoot('yarn.lock') → targetPaths.resolveRoot('yarn.lock') + + // After — for package-relative paths: + import { findOwnPaths } from '@backstage/cli-common'; + const own = findOwnPaths(__dirname); + // paths.ownDir → own.dir + // paths.ownRoot → own.rootDir + // paths.resolveOwn('config/jest.js') → own.resolve('config/jest.js') + // paths.resolveOwnRoot('tsconfig.json') → own.resolveRoot('tsconfig.json') + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.7 + +## @backstage/integration@1.21.0-next.0 + +### Minor Changes + +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog-backend@3.5.0-next.0 + +### Minor Changes + +- bf71677: Added opentelemetry metrics for SCM events: + + - `catalog.events.scm.messages` with attribute `eventType`: Counter for the number of SCM events actually received by the catalog backend. The `eventType` is currently either `location` or `repository`. + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- fbf382f: Minor internal optimisation +- 1ee5b28: Migrates existing catalog metrics to use the alpha MetricsService. This release is a 1:1 migration with no breaking changes. +- 3181973: Changed the `search` table foreign key to point to `final_entities` instead of `refresh_state` +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-catalog-node@2.1.0-next.0 + +### Minor Changes + +- bf71677: Added the ability for SCM events subscribers to mark the fact that they have taken actions based on events, which produces output metrics: + + - `catalog.events.scm.actions` with attribute `action`: Counter for the number of actions actually taken by catalog internals or other subscribers, based on SCM events. The `action` is currently either `create`, `delete`, `refresh`, or `move`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/backend-test-utils@1.11.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-notifications-backend-module-slack@0.4.0-next.0 + +### Minor Changes + +- 749ba60: Add an extension for custom Slack message layouts + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + +## @backstage/app-defaults@1.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/backend-app-api@1.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + +## @backstage/backend-defaults@0.15.3-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. +- b99158a: Fixed `yarn backstage-cli config:check --strict --config app-config.yaml` config validation error by adding + an optional `default` type discriminator to PostgreSQL connection configuration, + allowing `config:check` to properly validate `default` connection configurations. +- 1ee5b28: Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins. +- Updated dependencies + - @backstage/cli-node@0.2.19-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-app-api@1.5.1-next.0 + - @backstage/backend-dev-utils@0.1.7 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/backend-dynamic-feature-service@0.7.10-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.43-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-backend@0.5.12-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/backend-openapi-utils@0.6.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/backend-plugin-api@1.7.1-next.0 + +### Patch Changes + +- 1ee5b28: Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/backend-test-utils@1.11.1-next.0 + +### Patch Changes + +- 1ee5b28: Adds a new metrics service mock to be leveraged in tests +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-app-api@1.5.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/catalog-client@1.13.1-next.0 + +### Patch Changes + +- d2494d6: Minor update to catalog client docs +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + +## @backstage/cli@0.35.5-next.0 + +### Patch Changes + +- 246877a: Updated dependency `bfj` to `^9.0.2`. + +- bba2e49: Internal refactor to use new concurrency utilities from `@backstage/cli-node`. + +- fd50cb3: Added `translations export` and `translations import` commands for managing translation files. + + The `translations export` command discovers all `TranslationRef` definitions across frontend plugin dependencies and exports their default messages as JSON files. The `translations import` command generates `TranslationResource` wiring code from translated JSON files, ready to be plugged into the app. + + Both commands support a `--pattern` option for controlling the message file layout, for example `--pattern '{lang}/{id}.json'` for language-based directory grouping. + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. + +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. + +- 092b41f: Updated dependency `webpack` to `~5.105.0`. + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/eslint-plugin@0.2.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/module-federation-common@0.1.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.2 + +## @backstage/cli-node@0.2.19-next.0 + +### Patch Changes + +- 06c2015: Added `runConcurrentTasks` and `runWorkerQueueThreads` utilities, moved from the `@backstage/cli` internal code. +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/codemods@0.1.55-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + +## @backstage/config-loader@1.10.9-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/core-app-api@1.19.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + +## @backstage/core-compat-api@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + +## @backstage/core-components@0.18.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/version-bridge@1.0.12 + +## @backstage/core-plugin-api@1.12.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + +## @backstage/create-app@0.7.10-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + +## @backstage/dev-utils@1.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + +## @backstage/eslint-plugin@0.2.2-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 + +## @backstage/frontend-app-api@0.15.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + +## @backstage/frontend-defaults@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/errors@1.2.7 + - @backstage/frontend-app-api@0.15.1-next.0 + +## @backstage/frontend-dynamic-feature-loader@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/module-federation-common@0.1.0 + +## @backstage/frontend-plugin-api@0.14.2-next.0 + +### Patch Changes + +- 9c81af9: Made the `pluginId` property optional in the `FrontendFeature` type, allowing plugins published against older versions of the framework to be used without type errors. +- Updated dependencies + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + +## @backstage/frontend-test-utils@0.5.1-next.0 + +### Patch Changes + +- 909c742: Switched `MockTranslationApi` and related test utility imports from `@backstage/core-plugin-api/alpha` to the stable `@backstage/frontend-plugin-api` export. The `TranslationApi` type in the API report is now sourced from a single package. This has no effect on runtime behavior. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/integration-react@1.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/repo-tools@0.16.6-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- 2a51546: Fixed prettier existence checks in OpenAPI commands to use `fs.pathExists` instead of checking the resolved path string, which was always truthy. +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- 18a946c: Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + +## @techdocs/cli@1.10.6-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + +## @backstage/test-utils@1.7.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/ui@0.12.1-next.0 + +### Patch Changes + +- a1f4bee: Made Accordion a `bg` provider so nested components like Button auto-increment their background level. Updated `useDefinition` to resolve `bg` `propDef` defaults for provider components. + +- 8909359: Fixed focus-visible outline styles for Menu and Select components. + + **Affected components:** Menu, Select + +- 0f462f8: Improved type safety in `useDefinition` by centralizing prop resolution and strengthening the `BgPropsConstraint` to require that `bg` provider components declare `children` as a required prop in their OwnProps type. + +- 8909359: Added proper cursor styles for RadioGroup items. + + **Affected components:** RadioGroup + +- Updated dependencies + - @backstage/version-bridge@1.0.12 + +## @backstage/plugin-api-docs@0.13.5-next.0 + +### Patch Changes + +- 9c9d425: Fixed invisible text in parameter input fields when using dark mode in OpenAPI definition pages +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-app@0.4.1-next.0 + +### Patch Changes + +- 909c742: Switched translation API imports (`translationApiRef`, `appLanguageApiRef`) from the alpha `@backstage/core-plugin-api/alpha` path to the stable `@backstage/frontend-plugin-api` export. This has no effect on runtime behavior. +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-app-backend@0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.43-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-app-node@0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + +## @backstage/plugin-app-react@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/plugin-app-visualizer@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/plugin-auth@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + +## @backstage/plugin-auth-backend@0.27.1-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- 619be54: Update migrations to be reversible +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-openshift-provider@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-auth-node@0.6.14-next.0 + +## @backstage/plugin-auth-node@0.6.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/plugin-auth-react@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + +## @backstage/plugin-bitbucket-cloud-common@0.3.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + +## @backstage/plugin-catalog@1.33.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.4.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-kubernetes-common@0.9.10 + +## @backstage/plugin-catalog-backend-module-azure@0.3.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-bitbucket-cloud-common@0.3.8-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-kubernetes-common@0.9.10 + +## @backstage/plugin-catalog-backend-module-gerrit@0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-gitea@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-github@0.12.3-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.12.3-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.8.1-next.0 + +### Patch Changes + +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.8.1-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.7.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/plugin-catalog-backend-module-ldap@0.12.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-logs@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.13 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/plugin-catalog-graph@0.5.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + +## @backstage/plugin-catalog-import@0.13.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-catalog-react@2.0.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/frontend-test-utils@0.5.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.13 + - @backstage/plugin-devtools-react@0.1.2-next.0 + +## @backstage/plugin-config-schema@0.1.78-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/plugin-devtools@0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.22 + - @backstage/plugin-devtools-react@0.1.2-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-devtools-backend@0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-devtools-common@0.1.22 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-devtools-react@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/plugin-events-backend@0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-azure@0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-server@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-github@0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-google-pubsub@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-module-kafka@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-events-node@0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/plugin-gateway-backend@1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + +## @backstage/plugin-home@0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-home-react@0.1.36-next.0 + +## @backstage/plugin-home-react@0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/plugin-kubernetes@0.12.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-react@0.5.17-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-kubernetes-backend@0.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-node@0.4.2-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-react@0.5.17-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + +## @backstage/plugin-kubernetes-node@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + +## @backstage/plugin-kubernetes-react@0.5.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + +## @backstage/plugin-mcp-actions-backend@0.1.10-next.0 + +### Patch Changes + +- dc81af1: Adds two new metrics to track MCP server operations and sessions. + + - `mcp.server.operation.duration`: The duration taken to process an individual MCP operation + - `mcp.server.session.duration`: The duration of the MCP session from the perspective of the server + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + +## @backstage/plugin-mui-to-bui@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + +## @backstage/plugin-notifications@0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-signals-react@0.0.20-next.0 + +## @backstage/plugin-notifications-backend@0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + +## @backstage/plugin-notifications-backend-module-email@0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + +## @backstage/plugin-notifications-node@0.2.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-signals-node@0.1.29-next.0 + +## @backstage/plugin-org@0.6.50-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-catalog-common@1.1.8 + +## @backstage/plugin-org-react@0.1.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @backstage/plugin-permission-backend@0.7.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + +## @backstage/plugin-permission-node@0.10.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/plugin-permission-react@0.4.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/plugin-proxy-backend@0.6.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-proxy-node@0.1.13-next.0 + +## @backstage/plugin-proxy-node@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + +## @backstage/plugin-scaffolder@1.35.5-next.0 + +### Patch Changes + +- bd5b842: Added a new `ui:autoSelect` option to the EntityPicker field that controls whether an entity is automatically selected when the field loses focus. When set to `false`, the field will remain empty if the user closes it without explicitly selecting an entity, preventing unintentional selections. Defaults to `true` for backward compatibility. +- ee87720: Added back the `formFieldsApiRef` and `ScaffolderFormFieldsApi` alpha exports that were unintentionally removed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## @backstage/plugin-scaffolder-backend@3.1.4-next.0 + +### Patch Changes + +- 4e39e63: Removed unused dependencies +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.4-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.19-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-bitbucket-cloud-common@0.3.8-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.9.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.11.4-next.0 + +### Patch Changes + +- 5730c8e: Added `maskedAndHidden` option to `gitlab:projectVariable:create` and `publish:gitlab` action to support creating GitLab project variables that are both masked and hidden. Updated gitbeaker to version 43.8.0 for proper type support. +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.3.9-next.0 + +## @backstage/plugin-scaffolder-common@1.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + +## @backstage/plugin-scaffolder-node@0.12.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-test-utils@1.11.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + +## @backstage/plugin-scaffolder-react@1.19.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + +## @backstage/plugin-search@1.6.2-next.0 + +### Patch Changes + +- d5eb954: Fixes the search component not registering the first search on navigate to the search page. +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend@2.0.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-catalog@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-elasticsearch@1.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-explore@0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-pg@0.5.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-backend-module-techdocs@0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + +## @backstage/plugin-search-backend-node@1.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-search-react@1.10.5-next.0 + +### Patch Changes + +- d5eb954: Fixes the search component not registering the first search on navigate to the search page. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-search-common@1.2.22 + +## @backstage/plugin-signals@0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-signals-react@0.0.20-next.0 + +## @backstage/plugin-signals-backend@0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + +## @backstage/plugin-signals-node@0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + +## @backstage/plugin-signals-react@0.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + +## @backstage/plugin-techdocs@1.17.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@2.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## @backstage/plugin-techdocs-backend@2.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## @backstage/plugin-techdocs-node@1.14.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + +## @backstage/plugin-techdocs-react@1.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-techdocs-common@0.1.1 + +## @backstage/plugin-user-settings@0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-signals-react@0.0.20-next.0 + - @backstage/plugin-user-settings-common@0.1.0 + +## @backstage/plugin-user-settings-backend@0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + - @backstage/plugin-user-settings-common@0.1.0 + +## example-app@0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-search@1.6.2-next.0 + - @backstage/plugin-api-docs@0.13.5-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-scaffolder@1.35.5-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/plugin-app-visualizer@0.2.1-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-auth@0.1.6-next.0 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-catalog-graph@0.5.8-next.0 + - @backstage/plugin-catalog-import@0.13.11-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.27-next.0 + - @backstage/plugin-devtools@0.1.37-next.0 + - @backstage/plugin-home@0.9.3-next.0 + - @backstage/plugin-home-react@0.1.36-next.0 + - @backstage/plugin-kubernetes@0.12.17-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.35-next.0 + - @backstage/plugin-notifications@0.5.15-next.0 + - @backstage/plugin-org@0.6.50-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-signals@0.0.29-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.34-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + - @backstage/plugin-user-settings@0.9.1-next.0 + +## app-example-plugin@0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + +## example-app-legacy@0.2.119-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-search@1.6.2-next.0 + - @backstage/plugin-api-docs@0.13.5-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/plugin-scaffolder@1.35.5-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-mui-to-bui@0.2.5-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-catalog-graph@0.5.8-next.0 + - @backstage/plugin-catalog-import@0.13.11-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.27-next.0 + - @backstage/plugin-devtools@0.1.37-next.0 + - @backstage/plugin-home@0.9.3-next.0 + - @backstage/plugin-home-react@0.1.36-next.0 + - @backstage/plugin-kubernetes@0.12.17-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.35-next.0 + - @backstage/plugin-notifications@0.5.15-next.0 + - @backstage/plugin-org@0.6.50-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-signals@0.0.29-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.34-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + - @backstage/plugin-user-settings@0.9.1-next.0 + +## example-backend@0.0.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/plugin-scaffolder-backend@3.1.4-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-mcp-actions-backend@0.1.10-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-app-backend@0.5.12-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.5.1-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.17-next.0 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.12-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.20-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.18-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.9-next.0 + - @backstage/plugin-devtools-backend@0.5.15-next.0 + - @backstage/plugin-events-backend@0.5.12-next.0 + - @backstage/plugin-events-backend-module-google-pubsub@0.2.1-next.0 + - @backstage/plugin-kubernetes-backend@0.21.2-next.0 + - @backstage/plugin-notifications-backend@0.6.3-next.0 + - @backstage/plugin-permission-backend@0.7.10-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.17-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-proxy-backend@0.6.11-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.7-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.20-next.0 + - @backstage/plugin-search-backend@2.0.13-next.0 + - @backstage/plugin-search-backend-module-catalog@0.3.13-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.8.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.3.12-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.12-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-signals-backend@0.3.13-next.0 + - @backstage/plugin-techdocs-backend@2.1.6-next.0 + +## e2e-test@0.2.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/create-app@0.7.10-next.0 + - @backstage/errors@1.2.7 + +## @internal/frontend@0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + +## @internal/scaffolder@0.0.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + +## techdocs-cli-embedded-app@0.2.118-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + +## yarn-plugin-backstage@0.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/errors@1.2.7 + - @backstage/release-manifests@0.0.13 + +## @internal/plugin-todo-list@1.0.49-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + +## @internal/plugin-todo-list-backend@1.0.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 2a09cb1b11..085175c958 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -24,6 +24,7 @@ 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 +translations [command] Translation message management clean Delete cache directories [DEPRECATED] build-workspace [packages...] Builds a temporary dist workspace from the provided packages @@ -429,6 +430,73 @@ YAML file that can be referenced in the GitHub integration configuration. Usage: backstage-cli create-github-app ``` +## translations export + +Export translation messages from an app and all of its frontend plugins to JSON +files. This command must be run from within a package directory (e.g. +`packages/app`), not from the repository root. + +The command discovers all `TranslationRef` definitions in the dependency tree, +extracts their default messages using the TypeScript type system, and writes +them as JSON files along with a manifest. + +For more details on the translation workflow, see the +[Internationalization](../../plugins/internationalization.md) documentation. + +```text +Usage: backstage-cli translations export [options] + +Options: + --output Output directory for exported messages and manifest (default: "translations") + --pattern File path pattern for message files relative to the output + directory, with {id} and {lang} placeholders + (default: "messages/{id}.{lang}.json") + -h, --help display help for command +``` + +### Examples + +Export translations with default settings: + +```bash +cd packages/app +yarn backstage-cli translations export +``` + +Export with language-based directory grouping: + +```bash +yarn backstage-cli translations export --pattern '{lang}/{id}.json' +``` + +## translations import + +Generate translation resource wiring code from translated JSON files. Reads the +manifest and translated message files produced by `translations export`, and +generates a TypeScript module that creates `TranslationResource` objects for each +translated ref. + +The file pattern used during export is stored in the manifest and automatically +used by the import command. + +```text +Usage: backstage-cli translations import [options] + +Options: + --input Input directory containing the manifest and translated message files (default: "translations") + --output Output path for the generated wiring module (default: "src/translations/resources.ts") + -h, --help display help for command +``` + +### Examples + +Generate wiring code with default settings: + +```bash +cd packages/app +yarn backstage-cli translations import +``` + ## info Outputs debug information which is useful when opening an issue. Outputs system diff --git a/mkdocs.yml b/mkdocs.yml index c07ff5afc4..c18d74494a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -142,6 +142,7 @@ nav: - Composability System: 'plugins/composability.md' - Plugin Analytics: 'plugins/analytics.md' - Feature Flags: 'plugins/feature-flags.md' + - Internationalization (i18n): 'plugins/internationalization.md' - OpenAPI: - Schema-first plugins with OpenAPI (Experimental): 'openapi/01-getting-started.md' - Generate a client from your OpenAPI spec: 'openapi/generate-client.md' diff --git a/package.json b/package.json index 5a63fbc2db..7fcbb27ccb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.48.0", + "version": "1.49.0-next.0", "backstage": { "cli": { "new": { diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index a5516a33a9..e7bfdf0c89 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 1.7.5 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 71b5da64d7..b35830dbd1 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.7.5", + "version": "1.7.6-next.0", "description": "Provides the default wiring of a Backstage App", "backstage": { "role": "web-library" diff --git a/packages/app-example-plugin/CHANGELOG.md b/packages/app-example-plugin/CHANGELOG.md index a23772bb3b..f0784d88d2 100644 --- a/packages/app-example-plugin/CHANGELOG.md +++ b/packages/app-example-plugin/CHANGELOG.md @@ -1,5 +1,13 @@ # app-example-plugin +## 0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + ## 0.0.32 ### Patch Changes diff --git a/packages/app-example-plugin/package.json b/packages/app-example-plugin/package.json index 2bdfd931fd..93f2954355 100644 --- a/packages/app-example-plugin/package.json +++ b/packages/app-example-plugin/package.json @@ -1,6 +1,6 @@ { "name": "app-example-plugin", - "version": "0.0.32", + "version": "0.0.33-next.0", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-legacy/CHANGELOG.md b/packages/app-legacy/CHANGELOG.md index 2212011ecd..c0e84cb9d7 100644 --- a/packages/app-legacy/CHANGELOG.md +++ b/packages/app-legacy/CHANGELOG.md @@ -1,5 +1,49 @@ # example-app-legacy +## 0.2.119-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-search@1.6.2-next.0 + - @backstage/plugin-api-docs@0.13.5-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/plugin-scaffolder@1.35.5-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-mui-to-bui@0.2.5-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-catalog-graph@0.5.8-next.0 + - @backstage/plugin-catalog-import@0.13.11-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.27-next.0 + - @backstage/plugin-devtools@0.1.37-next.0 + - @backstage/plugin-home@0.9.3-next.0 + - @backstage/plugin-home-react@0.1.36-next.0 + - @backstage/plugin-kubernetes@0.12.17-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.35-next.0 + - @backstage/plugin-notifications@0.5.15-next.0 + - @backstage/plugin-org@0.6.50-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-signals@0.0.29-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.34-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + - @backstage/plugin-user-settings@0.9.1-next.0 + ## 0.2.118 ### Patch Changes diff --git a/packages/app-legacy/package.json b/packages/app-legacy/package.json index 6be63b7a14..4bdf649665 100644 --- a/packages/app-legacy/package.json +++ b/packages/app-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-app-legacy", - "version": "0.2.118", + "version": "0.2.119-next.0", "backstage": { "role": "frontend" }, diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index daa9908400..37e2dcfdb5 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,55 @@ # example-app +## 0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-search@1.6.2-next.0 + - @backstage/plugin-api-docs@0.13.5-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-scaffolder@1.35.5-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/plugin-app-visualizer@0.2.1-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-auth@0.1.6-next.0 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-catalog-graph@0.5.8-next.0 + - @backstage/plugin-catalog-import@0.13.11-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.27-next.0 + - @backstage/plugin-devtools@0.1.37-next.0 + - @backstage/plugin-home@0.9.3-next.0 + - @backstage/plugin-home-react@0.1.36-next.0 + - @backstage/plugin-kubernetes@0.12.17-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.35-next.0 + - @backstage/plugin-notifications@0.5.15-next.0 + - @backstage/plugin-org@0.6.50-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-signals@0.0.29-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.34-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + - @backstage/plugin-user-settings@0.9.1-next.0 + ## 0.0.32 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index b0d46befa8..7283f3064f 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.0.32", + "version": "0.0.33-next.0", "backstage": { "role": "frontend" }, diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index f1d26a7f4a..b07cb0869d 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-app-api +## 1.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + ## 1.5.0 ### Minor Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 97e5964e39..08b12d7d6d 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-app-api", - "version": "1.5.0", + "version": "1.5.1-next.0", "description": "Core API used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index da970f1f45..9ca1fae948 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/backend-defaults +## 0.15.3-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. +- b99158a: Fixed `yarn backstage-cli config:check --strict --config app-config.yaml` config validation error by adding + an optional `default` type discriminator to PostgreSQL connection configuration, + allowing `config:check` to properly validate `default` connection configurations. +- 1ee5b28: Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins. +- Updated dependencies + - @backstage/cli-node@0.2.19-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-app-api@1.5.1-next.0 + - @backstage/backend-dev-utils@0.1.7 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 0.15.2 ### Patch Changes diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index 64aabe5cc8..3d09146b0d 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -1127,6 +1127,36 @@ export interface Config { headers?: { [name: string]: string }; }; + /** + * Options for the metrics service. + */ + metrics?: { + /** + * Plugin-specific metrics configuration. Each plugin can override meter metadata. + */ + plugin?: { + [pluginId: string]: { + /** + * Meter configuration for this plugin. + */ + meter?: { + /** + * Custom meter name. If not set, defaults to backstage-plugin-{pluginId}. + */ + name?: string; + /** + * Version for the meter. + */ + version?: string; + /** + * Schema URL for the meter. + */ + schemaUrl?: string; + }; + }; + }; + }; + /** * Options to configure the default RootLoggerService. */ diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 6f705de7ba..1a7e6f7e41 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.15.2", + "version": "0.15.3-next.0", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" diff --git a/packages/backend-defaults/report-alpha.api.md b/packages/backend-defaults/report-alpha.api.md index c40517863a..352ec1d688 100644 --- a/packages/backend-defaults/report-alpha.api.md +++ b/packages/backend-defaults/report-alpha.api.md @@ -5,6 +5,7 @@ ```ts import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha'; import { ActionsService } from '@backstage/backend-plugin-api/alpha'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; import { RootSystemMetadataService } from '@backstage/backend-plugin-api/alpha'; import { ServiceFactory } from '@backstage/backend-plugin-api'; @@ -22,6 +23,13 @@ export const actionsServiceFactory: ServiceFactory< 'singleton' >; +// @alpha +export const metricsServiceFactory: ServiceFactory< + MetricsService, + 'plugin', + 'singleton' +>; + // @alpha export const rootSystemMetadataServiceFactory: ServiceFactory< RootSystemMetadataService, diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 9f8116a996..2b4ee5befa 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -38,6 +38,7 @@ import { eventsServiceFactory } from '@backstage/plugin-events-node'; import { actionsRegistryServiceFactory, actionsServiceFactory, + metricsServiceFactory, } from '@backstage/backend-defaults/alpha'; import { instanceMetadataServiceFactory } from './alpha/entrypoints/instanceMetadata/instanceMetadataServiceFactory'; @@ -66,6 +67,7 @@ export const defaultServiceFactories = [ // alpha services actionsRegistryServiceFactory, actionsServiceFactory, + metricsServiceFactory, // Unexported alpha services kept around for compatibility reasons instanceMetadataServiceFactory, diff --git a/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.test.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.test.ts new file mode 100644 index 0000000000..75e5104754 --- /dev/null +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2026 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 { metrics } from '@opentelemetry/api'; +import { DefaultMetricsService } from './DefaultMetricsService'; + +const mockGetMeter = jest.spyOn(metrics, 'getMeter'); + +describe('DefaultMetricsService', () => { + beforeEach(() => { + mockGetMeter.mockClear(); + }); + + describe('create', () => { + it('should create a MetricsService with name only', () => { + const service = DefaultMetricsService.create({ name: 'test-meter' }); + + expect(mockGetMeter).toHaveBeenCalledTimes(1); + expect(mockGetMeter).toHaveBeenCalledWith('test-meter', undefined, { + schemaUrl: undefined, + }); + + expect(service).toBeDefined(); + }); + + it('should create a MetricsService with name, version, and schemaUrl', () => { + const service = DefaultMetricsService.create({ + name: 'test-meter', + version: '1.2.3', + schemaUrl: 'https://example.com/schema', + }); + + expect(mockGetMeter).toHaveBeenCalledTimes(1); + expect(mockGetMeter).toHaveBeenCalledWith('test-meter', '1.2.3', { + schemaUrl: 'https://example.com/schema', + }); + + expect(service).toBeDefined(); + }); + }); + + describe('metric instruments', () => { + it('should create a counter', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const counter = service.createCounter('my_counter', { + description: 'A test counter', + unit: 'bytes', + }); + + expect(counter).toBeDefined(); + expect(counter.add).toBeDefined(); + }); + + it('should create an up-down counter', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const upDownCounter = service.createUpDownCounter('my_updown'); + + expect(upDownCounter).toBeDefined(); + expect(upDownCounter.add).toBeDefined(); + }); + + it('should create a histogram', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const histogram = service.createHistogram('my_histogram'); + + expect(histogram).toBeDefined(); + expect(histogram.record).toBeDefined(); + }); + + it('should create a gauge', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const gauge = service.createGauge('my_gauge'); + + expect(gauge).toBeDefined(); + expect(gauge.record).toBeDefined(); + }); + + it('should create an observable counter', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const counter = service.createObservableCounter('my_observable_counter'); + + expect(counter).toBeDefined(); + expect(counter.addCallback).toBeDefined(); + expect(counter.removeCallback).toBeDefined(); + }); + + it('should create an observable up-down counter', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const counter = service.createObservableUpDownCounter( + 'my_observable_updown', + ); + + expect(counter).toBeDefined(); + expect(counter.addCallback).toBeDefined(); + }); + + it('should create an observable gauge', () => { + const service = DefaultMetricsService.create({ name: 'test' }); + const gauge = service.createObservableGauge('my_observable_gauge'); + + expect(gauge).toBeDefined(); + expect(gauge.addCallback).toBeDefined(); + }); + }); +}); diff --git a/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.ts new file mode 100644 index 0000000000..764c6d6d1c --- /dev/null +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.ts @@ -0,0 +1,123 @@ +/* + * Copyright 2026 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 { Meter, metrics } from '@opentelemetry/api'; +import { + MetricsService, + MetricAttributes, + MetricOptions, + MetricsServiceCounter, + MetricsServiceUpDownCounter, + MetricsServiceHistogram, + MetricsServiceGauge, + MetricsServiceObservableCounter, + MetricsServiceObservableGauge, + MetricsServiceObservableUpDownCounter, +} from '@backstage/backend-plugin-api/alpha'; + +/** + * Options for creating a {@link DefaultMetricsService}. + * + * @alpha + */ +export interface DefaultMetricsServiceOptions { + name: string; + version?: string; + schemaUrl?: string; +} + +/** + * Default implementation of the {@link MetricsService} interface. + * + * This implementation provides a thin wrapper around the OpenTelemetry Meter API. + * + * @alpha + */ +export class DefaultMetricsService implements MetricsService { + private readonly meter: Meter; + + private constructor(opts: DefaultMetricsServiceOptions) { + // The meter name sets the OpenTelemetry Instrumentation Scope which identifies the source of metrics in telemetry backends. + this.meter = metrics.getMeter(opts.name, opts.version, { + schemaUrl: opts.schemaUrl, + }); + } + + /** + * Creates a new {@link MetricsService} instance. + * + * @param opts - Options for configuring the meter scope + * @returns A new MetricsService instance + */ + static create(opts: DefaultMetricsServiceOptions): MetricsService { + return new DefaultMetricsService(opts); + } + + createCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceCounter { + return this.meter.createCounter(name, opts); + } + + createUpDownCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceUpDownCounter { + return this.meter.createUpDownCounter(name, opts); + } + + createHistogram( + name: string, + opts?: MetricOptions, + ): MetricsServiceHistogram { + return this.meter.createHistogram(name, opts); + } + + createGauge( + name: string, + opts?: MetricOptions, + ): MetricsServiceGauge { + return this.meter.createGauge(name, opts); + } + + createObservableCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableCounter { + return this.meter.createObservableCounter(name, opts); + } + + createObservableUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableUpDownCounter { + return this.meter.createObservableUpDownCounter(name, opts); + } + + createObservableGauge< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableGauge { + return this.meter.createObservableGauge(name, opts); + } +} diff --git a/packages/cli/src/lib/paths.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts similarity index 75% rename from packages/cli/src/lib/paths.ts rename to packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts index 2c658c27b3..fc3e04a855 100644 --- a/packages/cli/src/lib/paths.ts +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2026 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. @@ -13,8 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); +export { metricsServiceFactory } from './metricsServiceFactory'; diff --git a/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.test.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.test.ts new file mode 100644 index 0000000000..854fcfd389 --- /dev/null +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.test.ts @@ -0,0 +1,130 @@ +/* + * Copyright 2026 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 { + mockServices, + ServiceFactoryTester, +} from '@backstage/backend-test-utils'; +import { metricsServiceFactory } from './metricsServiceFactory'; +import { DefaultMetricsService } from './DefaultMetricsService'; + +describe('metricsServiceFactory', () => { + let createSpy: jest.SpyInstance; + + beforeEach(() => { + createSpy = jest.spyOn(DefaultMetricsService, 'create'); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + const defaultServices = [ + mockServices.rootConfig.factory(), + metricsServiceFactory, + ]; + + it('should use backstage-plugin-{pluginId} as meter name when no config is set', async () => { + await ServiceFactoryTester.from(metricsServiceFactory, { + dependencies: defaultServices, + }).getSubject('my-plugin'); + + expect(createSpy).toHaveBeenCalledWith({ + name: 'backstage-plugin-my-plugin', + version: undefined, + schemaUrl: undefined, + }); + }); + + it('should use custom name from config', async () => { + await ServiceFactoryTester.from(metricsServiceFactory, { + dependencies: [ + mockServices.rootConfig.factory({ + data: { + backend: { + metrics: { + plugin: { + 'my-plugin': { + meter: { + name: 'custom-metrics-name', + }, + }, + }, + }, + }, + }, + }), + metricsServiceFactory, + ], + }).getSubject('my-plugin'); + + expect(createSpy).toHaveBeenCalledWith({ + name: 'custom-metrics-name', + version: undefined, + schemaUrl: undefined, + }); + }); + + it('should accept version and schemaUrl from config', async () => { + await ServiceFactoryTester.from(metricsServiceFactory, { + dependencies: [ + mockServices.rootConfig.factory({ + data: { + backend: { + metrics: { + plugin: { + 'my-plugin': { + meter: { + name: 'my-plugin-metrics', + version: '1.2.3', + schemaUrl: 'https://example.com/schema', + }, + }, + }, + }, + }, + }, + }), + metricsServiceFactory, + ], + }).getSubject('my-plugin'); + + expect(createSpy).toHaveBeenCalledWith({ + name: 'my-plugin-metrics', + version: '1.2.3', + schemaUrl: 'https://example.com/schema', + }); + }); + + it('should implement the full MetricsService interface', async () => { + const subject = await ServiceFactoryTester.from(metricsServiceFactory, { + dependencies: defaultServices, + }).getSubject('test-plugin'); + + expect(createSpy).toHaveBeenCalledWith({ + name: 'backstage-plugin-test-plugin', + version: undefined, + schemaUrl: undefined, + }); + + expect(subject.createCounter).toBeDefined(); + expect(subject.createUpDownCounter).toBeDefined(); + expect(subject.createHistogram).toBeDefined(); + expect(subject.createGauge).toBeDefined(); + expect(subject.createObservableCounter).toBeDefined(); + expect(subject.createObservableUpDownCounter).toBeDefined(); + expect(subject.createObservableGauge).toBeDefined(); + }); +}); diff --git a/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.ts new file mode 100644 index 0000000000..a62ad0411a --- /dev/null +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2025 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 { metricsServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { DefaultMetricsService } from './DefaultMetricsService'; + +/** + * Service factory for collecting plugin-scoped metrics. + * + * @alpha + */ +export const metricsServiceFactory = createServiceFactory({ + service: metricsServiceRef, + deps: { + config: coreServices.rootConfig, + pluginMetadata: coreServices.pluginMetadata, + }, + factory: ({ config, pluginMetadata }) => { + const pluginId = pluginMetadata.getId(); + + const meterConfig = config.getOptionalConfig( + `backend.metrics.plugin.${pluginId}.meter`, + ); + const scopeName = `backstage-plugin-${pluginId}`; + const name = meterConfig?.getOptionalString('name') ?? scopeName; + const version = meterConfig?.getOptionalString('version'); + const schemaUrl = meterConfig?.getOptionalString('schemaUrl'); + + return DefaultMetricsService.create({ name, version, schemaUrl }); + }, +}); diff --git a/packages/backend-defaults/src/alpha/index.ts b/packages/backend-defaults/src/alpha/index.ts index c17e0e71cb..1d0ec158af 100644 --- a/packages/backend-defaults/src/alpha/index.ts +++ b/packages/backend-defaults/src/alpha/index.ts @@ -16,4 +16,5 @@ export { actionsRegistryServiceFactory } from './entrypoints/actionsRegistry'; export { actionsServiceFactory } from './entrypoints/actions'; +export { metricsServiceFactory } from './entrypoints/metrics'; export { rootSystemMetadataServiceFactory } from './entrypoints/rootSystemMetadata'; diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index a9be5cd0ba..24c8b882db 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/backend-dynamic-feature-service +## 0.7.10-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.43-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-backend@0.5.12-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 0.7.9 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index c197ad041c..2ba6bbc68f 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dynamic-feature-service", - "version": "0.7.9", + "version": "0.7.10-next.0", "description": "Backstage dynamic feature service", "backstage": { "role": "node-library" diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts index 1f8fa2cfd6..aee492b1b7 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts @@ -38,7 +38,7 @@ import { createSpecializedBackend } from '@backstage/backend-app-api'; import { ConfigSources } from '@backstage/config-loader'; import { Logs, MockedLogger, LogContent } from '../__testUtils__/testUtils'; import { PluginScanner } from '../scanner/plugin-scanner'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; @@ -956,7 +956,7 @@ describe('backend-dynamic-feature-service', () => { mockDir.setContent({ 'package.json': fs.readFileSync( - findPaths(__dirname).resolveTargetRoot('package.json'), + targetPaths.resolveRoot('package.json'), ), 'dynamic-plugins-root': {}, 'dynamic-plugins-root/a-dynamic-plugin': ctx => @@ -1044,7 +1044,7 @@ describe('backend-dynamic-feature-service', () => { otherMockDir.resolve('a-dynamic-plugin'), ); expect(mockedModuleLoader.bootstrap).toHaveBeenCalledWith( - findPaths(__dirname).targetRoot, + targetPaths.rootDir, [realPath], new Map([ [ diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts index c4cb33892d..b79a796eb9 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts @@ -35,7 +35,7 @@ import { createServiceRef, } from '@backstage/backend-plugin-api'; import { PackageRole, PackageRoles } from '@backstage/cli-node'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; import * as fs from 'node:fs'; /** @@ -56,7 +56,7 @@ export class DynamicPluginManager implements DynamicPluginProvider { options: DynamicPluginManagerOptions, ): Promise { /* eslint-disable-next-line no-restricted-syntax */ - const backstageRoot = findPaths(__dirname).targetRoot; + const backstageRoot = targetPaths.rootDir; const scanner = PluginScanner.create({ config: options.config, logger: options.logger, diff --git a/packages/backend-dynamic-feature-service/src/schemas/schemas.ts b/packages/backend-dynamic-feature-service/src/schemas/schemas.ts index d50742f8fb..400f57829a 100644 --- a/packages/backend-dynamic-feature-service/src/schemas/schemas.ts +++ b/packages/backend-dynamic-feature-service/src/schemas/schemas.ts @@ -20,7 +20,7 @@ import { createServiceFactory, createServiceRef, } from '@backstage/backend-plugin-api'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; import * as path from 'node:path'; @@ -100,7 +100,7 @@ const dynamicPluginsSchemasServiceFactoryWithOptions = ( config, logger, // eslint-disable-next-line no-restricted-syntax - backstageRoot: findPaths(__dirname).targetRoot, + backstageRoot: targetPaths.rootDir, preferAlpha: true, }); diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index 58436b3235..ce142b728e 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-openapi-utils +## 0.6.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.6.6 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 5c6a9c5773..1f5bc417a8 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-openapi-utils", - "version": "0.6.6", + "version": "0.6.7-next.0", "description": "OpenAPI typescript support.", "backstage": { "role": "node-library" diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 94768add54..b100b47e26 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/backend-plugin-api +## 1.7.1-next.0 + +### Patch Changes + +- 1ee5b28: Adds an alpha `MetricsService` to provide a unified interface for metrics instrumentation across Backstage plugins. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 1.7.0 ### Minor Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 131f24bafb..6acc8a384b 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-plugin-api", - "version": "1.7.0", + "version": "1.7.1-next.0", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" diff --git a/packages/backend-plugin-api/report-alpha.api.md b/packages/backend-plugin-api/report-alpha.api.md index e06e0c45d2..7d6786b97e 100644 --- a/packages/backend-plugin-api/report-alpha.api.md +++ b/packages/backend-plugin-api/report-alpha.api.md @@ -103,6 +103,150 @@ export const actionsServiceRef: ServiceRef< 'singleton' >; +// @alpha +export interface MetricAdvice { + explicitBucketBoundaries?: number[]; +} + +// @alpha +export interface MetricAttributes { + // (undocumented) + [attributeKey: string]: MetricAttributeValue | undefined; +} + +// @alpha +export type MetricAttributeValue = + | string + | number + | boolean + | Array + | Array + | Array; + +// @alpha +export interface MetricOptions { + advice?: MetricAdvice; + description?: string; + unit?: string; +} + +// @alpha +export interface MetricsService { + createCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceCounter; + createGauge( + name: string, + opts?: MetricOptions, + ): MetricsServiceGauge; + createHistogram( + name: string, + opts?: MetricOptions, + ): MetricsServiceHistogram; + createObservableCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableCounter; + createObservableGauge< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableGauge; + createObservableUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableUpDownCounter; + createUpDownCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceUpDownCounter; +} + +// @alpha +export interface MetricsServiceCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + add(value: number, attributes?: TAttributes): void; +} + +// @alpha +export interface MetricsServiceGauge< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + record(value: number, attributes?: TAttributes): void; +} + +// @alpha +export interface MetricsServiceHistogram< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + record(value: number, attributes?: TAttributes): void; +} + +// @alpha +export interface MetricsServiceObservable< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + addCallback(callback: MetricsServiceObservableCallback): void; + // (undocumented) + removeCallback(callback: MetricsServiceObservableCallback): void; +} + +// @alpha +export type MetricsServiceObservableCallback< + TAttributes extends MetricAttributes = MetricAttributes, +> = ( + observableResult: MetricsServiceObservableResult, +) => void | Promise; + +// @alpha +export type MetricsServiceObservableCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +// @alpha +export type MetricsServiceObservableGauge< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +// @alpha +export interface MetricsServiceObservableResult< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + observe(value: number, attributes?: TAttributes): void; +} + +// @alpha +export type MetricsServiceObservableUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +// @alpha +export const metricsServiceRef: ServiceRef< + MetricsService, + 'plugin', + 'singleton' +>; + +// @alpha +export interface MetricsServiceUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> { + // (undocumented) + add(value: number, attributes?: TAttributes): void; +} + // @public (undocumented) export interface RootSystemMetadataService { // (undocumented) diff --git a/packages/backend-plugin-api/src/alpha/MetricsService.ts b/packages/backend-plugin-api/src/alpha/MetricsService.ts new file mode 100644 index 0000000000..1c92ea9e09 --- /dev/null +++ b/packages/backend-plugin-api/src/alpha/MetricsService.ts @@ -0,0 +1,273 @@ +/* + * Copyright 2026 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. + */ + +/** + * Attribute values that can be attached to metric measurements. + * + * @alpha + */ +export type MetricAttributeValue = + | string + | number + | boolean + | Array + | Array + | Array; + +/** + * A set of key-value pairs that can be attached to metric measurements. + * + * @alpha + */ +export interface MetricAttributes { + [attributeKey: string]: MetricAttributeValue | undefined; +} + +/** + * Advisory options that influence aggregation configuration. + * + * @alpha + */ +export interface MetricAdvice { + /** + * Hint the explicit bucket boundaries for histogram aggregation. + */ + explicitBucketBoundaries?: number[]; +} + +/** + * Options for creating a metric instrument. + * + * @alpha + */ +export interface MetricOptions { + /** + * The description of the Metric. + */ + description?: string; + /** + * The unit of the Metric values. + */ + unit?: string; + /** + * Advisory options that influence aggregation configuration. + */ + advice?: MetricAdvice; +} + +/** + * A counter metric that only supports non-negative increments. + * + * @alpha + */ +export interface MetricsServiceCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> { + add(value: number, attributes?: TAttributes): void; +} + +/** + * A counter metric that supports both positive and negative increments. + * + * @alpha + */ +export interface MetricsServiceUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> { + add(value: number, attributes?: TAttributes): void; +} + +/** + * A histogram metric for recording distributions of values. + * + * @alpha + */ +export interface MetricsServiceHistogram< + TAttributes extends MetricAttributes = MetricAttributes, +> { + record(value: number, attributes?: TAttributes): void; +} + +/** + * A gauge metric for recording instantaneous values. + * + * @alpha + */ +export interface MetricsServiceGauge< + TAttributes extends MetricAttributes = MetricAttributes, +> { + record(value: number, attributes?: TAttributes): void; +} + +/** + * The result object passed to observable metric callbacks. + * + * @alpha + */ +export interface MetricsServiceObservableResult< + TAttributes extends MetricAttributes = MetricAttributes, +> { + observe(value: number, attributes?: TAttributes): void; +} + +/** + * A callback function for observable metrics. Called whenever a metric + * collection is initiated. + * + * @alpha + */ +export type MetricsServiceObservableCallback< + TAttributes extends MetricAttributes = MetricAttributes, +> = ( + observableResult: MetricsServiceObservableResult, +) => void | Promise; + +/** + * An observable metric instrument that reports values via callbacks. + * + * @alpha + */ +export interface MetricsServiceObservable< + TAttributes extends MetricAttributes = MetricAttributes, +> { + addCallback(callback: MetricsServiceObservableCallback): void; + removeCallback(callback: MetricsServiceObservableCallback): void; +} + +/** + * An observable counter metric that reports non-negative sums via callbacks. + * + * @alpha + */ +export type MetricsServiceObservableCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +/** + * An observable counter metric that reports sums that can go up or down + * via callbacks. + * + * @alpha + */ +export type MetricsServiceObservableUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +/** + * An observable gauge metric that reports instantaneous values via callbacks. + * + * @alpha + */ +export type MetricsServiceObservableGauge< + TAttributes extends MetricAttributes = MetricAttributes, +> = MetricsServiceObservable; + +/** + * A service that provides a facility for emitting metrics. + * + * @alpha + */ +export interface MetricsService { + /** + * Creates a new counter metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The counter metric. + */ + createCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceCounter; + + /** + * Creates a new up-down counter metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The up-down counter metric. + */ + createUpDownCounter( + name: string, + opts?: MetricOptions, + ): MetricsServiceUpDownCounter; + + /** + * Creates a new histogram metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The histogram metric. + */ + createHistogram( + name: string, + opts?: MetricOptions, + ): MetricsServiceHistogram; + + /** + * Creates a new gauge metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The gauge metric. + */ + createGauge( + name: string, + opts?: MetricOptions, + ): MetricsServiceGauge; + + /** + * Creates a new observable counter metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The observable counter metric. + */ + createObservableCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableCounter; + + /** + * Creates a new observable up-down counter metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The observable up-down counter metric. + */ + createObservableUpDownCounter< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableUpDownCounter; + + /** + * Creates a new observable gauge metric. + * + * @param name - The name of the metric. + * @param opts - The options for the metric. + * @returns The observable gauge metric. + */ + createObservableGauge< + TAttributes extends MetricAttributes = MetricAttributes, + >( + name: string, + opts?: MetricOptions, + ): MetricsServiceObservableGauge; +} diff --git a/packages/backend-plugin-api/src/alpha/index.ts b/packages/backend-plugin-api/src/alpha/index.ts index 56f02f5275..c487686338 100644 --- a/packages/backend-plugin-api/src/alpha/index.ts +++ b/packages/backend-plugin-api/src/alpha/index.ts @@ -27,8 +27,27 @@ export type { export type { ActionsService, ActionsServiceAction } from './ActionsService'; +export type { + MetricsService, + MetricAdvice, + MetricAttributes, + MetricAttributeValue, + MetricOptions, + MetricsServiceCounter, + MetricsServiceUpDownCounter, + MetricsServiceHistogram, + MetricsServiceGauge, + MetricsServiceObservable, + MetricsServiceObservableCallback, + MetricsServiceObservableCounter, + MetricsServiceObservableGauge, + MetricsServiceObservableResult, + MetricsServiceObservableUpDownCounter, +} from './MetricsService'; + export { actionsRegistryServiceRef, actionsServiceRef, + metricsServiceRef, rootSystemMetadataServiceRef, } from './refs'; diff --git a/packages/backend-plugin-api/src/alpha/refs.ts b/packages/backend-plugin-api/src/alpha/refs.ts index a890271364..bd87ea8467 100644 --- a/packages/backend-plugin-api/src/alpha/refs.ts +++ b/packages/backend-plugin-api/src/alpha/refs.ts @@ -56,3 +56,14 @@ export const rootSystemMetadataServiceRef = createServiceRef< id: 'alpha.core.rootSystemMetadata', scope: 'root', }); + +/** + * Service for managing metrics. + * + * @alpha + */ +export const metricsServiceRef = createServiceRef< + import('./MetricsService').MetricsService +>({ + id: 'alpha.core.metrics', +}); diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 0b144df1da..4e9f955a83 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/backend-test-utils +## 1.11.1-next.0 + +### Patch Changes + +- 1ee5b28: Adds a new metrics service mock to be leveraged in tests +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-app-api@1.5.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + ## 1.11.0 ### Minor Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index ee65ddbc78..a4fe84b9c0 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-test-utils", - "version": "1.11.0", + "version": "1.11.1-next.0", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" diff --git a/packages/backend-test-utils/report-alpha.api.md b/packages/backend-test-utils/report-alpha.api.md index ca6f47191d..b6bf9e883d 100644 --- a/packages/backend-test-utils/report-alpha.api.md +++ b/packages/backend-test-utils/report-alpha.api.md @@ -12,6 +12,7 @@ import { BackstageCredentials } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; import { ServiceFactory } from '@backstage/backend-plugin-api'; // @alpha (undocumented) @@ -43,6 +44,16 @@ export namespace actionsServiceMock { ) => ServiceMock; } +// @alpha (undocumented) +export namespace metricsServiceMock { + const // (undocumented) + factory: () => ServiceFactory; + const // (undocumented) + mock: ( + partialImpl?: Partial | undefined, + ) => ServiceMock; +} + // @alpha export class MockActionsRegistry implements ActionsRegistryService, ActionsService diff --git a/packages/backend-test-utils/src/alpha/services/MetricsServiceMock.ts b/packages/backend-test-utils/src/alpha/services/MetricsServiceMock.ts new file mode 100644 index 0000000000..301d47fb2e --- /dev/null +++ b/packages/backend-test-utils/src/alpha/services/MetricsServiceMock.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2025 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 { createServiceMock } from './alphaCreateServiceMock'; +import { + MetricsService, + metricsServiceRef, +} from '@backstage/backend-plugin-api/alpha'; +import { metricsServiceFactory } from '@backstage/backend-defaults/alpha'; + +/** + * @alpha + */ +export namespace metricsServiceMock { + export const factory = () => metricsServiceFactory; + + export const mock = createServiceMock( + metricsServiceRef, + () => ({ + createCounter: jest.fn().mockImplementation(() => ({ + add: jest.fn(), + })), + createUpDownCounter: jest.fn().mockImplementation(() => ({ + add: jest.fn(), + })), + createHistogram: jest.fn().mockImplementation(() => ({ + record: jest.fn(), + })), + createGauge: jest.fn().mockImplementation(() => ({ + record: jest.fn(), + })), + createObservableCounter: jest.fn().mockImplementation(() => ({ + addCallback: jest.fn(), + removeCallback: jest.fn(), + })), + createObservableUpDownCounter: jest.fn().mockImplementation(() => ({ + addCallback: jest.fn(), + removeCallback: jest.fn(), + })), + createObservableGauge: jest.fn().mockImplementation(() => ({ + addCallback: jest.fn(), + removeCallback: jest.fn(), + })), + }), + ); +} diff --git a/packages/backend-test-utils/src/alpha/services/index.ts b/packages/backend-test-utils/src/alpha/services/index.ts index ac92033ff8..527bb1822f 100644 --- a/packages/backend-test-utils/src/alpha/services/index.ts +++ b/packages/backend-test-utils/src/alpha/services/index.ts @@ -17,4 +17,5 @@ export { actionsRegistryServiceMock } from './ActionsRegistryServiceMock'; export { MockActionsRegistry } from './MockActionsRegistry'; export { actionsServiceMock } from './ActionsServiceMock'; +export { metricsServiceMock } from './MetricsServiceMock'; export { type ServiceMock } from './alphaCreateServiceMock'; diff --git a/packages/backend-test-utils/src/wiring/TestBackend.ts b/packages/backend-test-utils/src/wiring/TestBackend.ts index 43a63a49e5..11decb883d 100644 --- a/packages/backend-test-utils/src/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/wiring/TestBackend.ts @@ -43,6 +43,7 @@ import { HostDiscovery } from '@backstage/backend-defaults/discovery'; import { actionsRegistryServiceMock, actionsServiceMock, + metricsServiceMock, } from '../alpha/services'; /** @public */ @@ -92,6 +93,7 @@ export const defaultServiceFactories = [ // Alpha services actionsRegistryServiceMock.factory(), actionsServiceMock.factory(), + metricsServiceMock.factory(), ]; /** diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 27ef95a0f3..b871e48357 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,47 @@ # example-backend +## 0.0.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/plugin-scaffolder-backend@3.1.4-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-mcp-actions-backend@0.1.10-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-app-backend@0.5.12-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.5.1-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.17-next.0 + - @backstage/plugin-auth-backend-module-openshift-provider@0.1.5-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.5.12-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.20-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.18-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.6.9-next.0 + - @backstage/plugin-devtools-backend@0.5.15-next.0 + - @backstage/plugin-events-backend@0.5.12-next.0 + - @backstage/plugin-events-backend-module-google-pubsub@0.2.1-next.0 + - @backstage/plugin-kubernetes-backend@0.21.2-next.0 + - @backstage/plugin-notifications-backend@0.6.3-next.0 + - @backstage/plugin-permission-backend@0.7.10-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.17-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-proxy-backend@0.6.11-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.9.7-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.20-next.0 + - @backstage/plugin-search-backend@2.0.13-next.0 + - @backstage/plugin-search-backend-module-catalog@0.3.13-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.8.1-next.0 + - @backstage/plugin-search-backend-module-explore@0.3.12-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.4.12-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-signals-backend@0.3.13-next.0 + - @backstage/plugin-techdocs-backend@2.1.6-next.0 + ## 0.0.47 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index b6b97f214e..b53b1933bb 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.47", + "version": "0.0.48-next.0", "backstage": { "role": "backend" }, diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 563a0ef828..03f4e627b2 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/catalog-client +## 1.13.1-next.0 + +### Patch Changes + +- d2494d6: Minor update to catalog client docs +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + ## 1.13.0 ### Minor Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 1a299182e8..9ca0335241 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "1.13.0", + "version": "1.13.1-next.0", "description": "An isomorphic client for the catalog backend", "backstage": { "role": "common-library" diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index a537e8b3a5..b45bef8bbd 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -535,9 +535,7 @@ export class CatalogClient implements CatalogApi { } while (cursor); } - // - // Private methods - // + // #region Private methods private async requestIgnored(response: Response): Promise { if (!response.ok) { @@ -588,4 +586,6 @@ export class CatalogClient implements CatalogApi { } return filters; } + + // #endregion } diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index 12c5e00c03..c766b094b8 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -24,7 +24,7 @@ import { FilterPredicate } from '@backstage/filter-predicates'; /** * This symbol can be used in place of a value when passed to filters in e.g. - * {@link CatalogClient.getEntities}, to signify that you want to filter on the + * {@link CatalogApi.getEntities}, to signify that you want to filter on the * presence of that key no matter what its value is. * * @public @@ -146,7 +146,7 @@ export type EntityOrderQuery = }>; /** - * The request type for {@link CatalogClient.getEntities}. + * The request type for {@link CatalogApi.getEntities}. * * @public */ @@ -180,7 +180,7 @@ export interface GetEntitiesRequest { } /** - * The response type for {@link CatalogClient.getEntities}. + * The response type for {@link CatalogApi.getEntities}. * * @public */ @@ -189,7 +189,7 @@ export interface GetEntitiesResponse { } /** - * The request type for {@link CatalogClient.getEntitiesByRefs}. + * The request type for {@link CatalogApi.getEntitiesByRefs}. * * @public */ @@ -200,7 +200,7 @@ export interface GetEntitiesByRefsRequest { * @remarks * * The returned list of entities will be in the same order as the refs, and - * null will be returned in those positions that were not found. + * undefined will be returned in those positions that were not found. */ entityRefs: string[]; /** @@ -215,7 +215,7 @@ export interface GetEntitiesByRefsRequest { } /** - * The response type for {@link CatalogClient.getEntitiesByRefs}. + * The response type for {@link CatalogApi.getEntitiesByRefs}. * * @public */ @@ -226,13 +226,13 @@ export interface GetEntitiesByRefsResponse { * @remarks * * The list will be in the same order as the refs given in the request, and - * null will be returned in those positions that were not found. + * undefined will be returned in those positions that were not found. */ items: Array; } /** - * The request type for {@link CatalogClient.getEntityAncestors}. + * The request type for {@link CatalogApi.getEntityAncestors}. * * @public */ @@ -241,7 +241,7 @@ export interface GetEntityAncestorsRequest { } /** - * The response type for {@link CatalogClient.getEntityAncestors}. + * The response type for {@link CatalogApi.getEntityAncestors}. * * @public */ @@ -254,7 +254,7 @@ export interface GetEntityAncestorsResponse { } /** - * The request type for {@link CatalogClient.getEntityFacets}. + * The request type for {@link CatalogApi.getEntityFacets}. * * @public */ @@ -323,7 +323,7 @@ export interface GetEntityFacetsRequest { } /** - * The response type for {@link CatalogClient.getEntityFacets}. + * The response type for {@link CatalogApi.getEntityFacets}. * * @public */ @@ -355,7 +355,7 @@ export type Location = { }; /** - * The response type for {@link CatalogClient.getLocations} + * The response type for {@link CatalogApi.getLocations} * * @public */ @@ -364,7 +364,7 @@ export interface GetLocationsResponse { } /** - * The request type for {@link CatalogClient.addLocation}. + * The request type for {@link CatalogApi.addLocation}. * * @public */ @@ -379,7 +379,7 @@ export type AddLocationRequest = { }; /** - * The response type for {@link CatalogClient.addLocation}. + * The response type for {@link CatalogApi.addLocation}. * * @public */ @@ -396,7 +396,7 @@ export type AddLocationResponse = { }; /** - * The response type for {@link CatalogClient.validateEntity} + * The response type for {@link CatalogApi.validateEntity} * * @public */ @@ -405,7 +405,7 @@ export type ValidateEntityResponse = | { valid: false; errors: SerializedError[] }; /** - * The request type for {@link CatalogClient.queryEntities}. + * The request type for {@link CatalogApi.queryEntities}. * * @public */ @@ -414,7 +414,7 @@ export type QueryEntitiesRequest = | QueryEntitiesCursorRequest; /** - * A request type for {@link CatalogClient.queryEntities}. + * A request type for {@link CatalogApi.queryEntities}. * The method takes this type in an initial pagination request, * when requesting the first batch of entities. * @@ -436,7 +436,7 @@ export type QueryEntitiesInitialRequest = { }; /** - * A request type for {@link CatalogClient.queryEntities}. + * A request type for {@link CatalogApi.queryEntities}. * The method takes this type in a pagination request, following * the initial request. * @@ -449,7 +449,7 @@ export type QueryEntitiesCursorRequest = { }; /** - * The response type for {@link CatalogClient.queryEntities}. + * The response type for {@link CatalogApi.queryEntities}. * * @public */ @@ -467,7 +467,7 @@ export type QueryEntitiesResponse = { }; /** - * Stream entities request for {@link CatalogClient.streamEntities}. + * Stream entities request for {@link CatalogApi.streamEntities}. * * @public */ @@ -546,7 +546,7 @@ export interface CatalogApi { * * The output list of entities is of the same size and in the same order as * the requested list of entity refs. Entries that are not found are returned - * as null. + * as undefined. * * @param request - Request parameters * @param options - Additional options diff --git a/packages/catalog-client/src/types/discovery.ts b/packages/catalog-client/src/types/discovery.ts index 19f304b1fd..3755e0d529 100644 --- a/packages/catalog-client/src/types/discovery.ts +++ b/packages/catalog-client/src/types/discovery.ts @@ -15,7 +15,9 @@ */ /** - * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + * This is a structurally similar version of `DiscoveryApi` / + * `DiscoveryService`, used here to avoid dependencies on the frontend or + * backend plugin API packages and allowing both of those forms to be passed in. */ export type DiscoveryApi = { getBaseUrl(pluginId: string): Promise; diff --git a/packages/catalog-client/src/types/fetch.ts b/packages/catalog-client/src/types/fetch.ts index 047a9f3558..a99140b749 100644 --- a/packages/catalog-client/src/types/fetch.ts +++ b/packages/catalog-client/src/types/fetch.ts @@ -15,7 +15,9 @@ */ /** - * This is a copy of FetchApi, to avoid importing core-plugin-api. + * This is a structurally similar version of `FetchApi`, used here to avoid + * dependencies on the frontend or backend plugin API packages and allowing both + * of those forms to be passed in. */ export type FetchApi = { fetch: typeof fetch; diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index c36322d60f..6f527693b4 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/cli-common +## 0.2.0-next.0 + +### Minor Changes + +- 56bd494: Added `targetPaths` and `findOwnPaths` as replacements for `findPaths`, with a cleaner separation between target project paths and package-relative paths. + + To migrate existing `findPaths` usage: + + ```ts + // Before + import { findPaths } from '@backstage/cli-common'; + const paths = findPaths(__dirname); + + // After — for target project paths (cwd-based): + import { targetPaths } from '@backstage/cli-common'; + // paths.targetDir → targetPaths.dir + // paths.targetRoot → targetPaths.rootDir + // paths.resolveTarget('src') → targetPaths.resolve('src') + // paths.resolveTargetRoot('yarn.lock') → targetPaths.resolveRoot('yarn.lock') + + // After — for package-relative paths: + import { findOwnPaths } from '@backstage/cli-common'; + const own = findOwnPaths(__dirname); + // paths.ownDir → own.dir + // paths.ownRoot → own.rootDir + // paths.resolveOwn('config/jest.js') → own.resolve('config/jest.js') + // paths.resolveOwnRoot('tsconfig.json') → own.resolveRoot('tsconfig.json') + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.7 + ## 0.1.18 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 9134eeeaee..4e38607467 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,14 +1,12 @@ { "name": "@backstage/cli-common", - "version": "0.1.18", + "version": "0.2.0-next.0", "description": "Common functionality used by cli, backend, and create-app", "backstage": { "role": "node-library" }, "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" + "access": "public" }, "keywords": [ "backstage" @@ -20,8 +18,23 @@ "directory": "packages/cli-common" }, "license": "Apache-2.0", + "exports": { + ".": "./src/index.ts", + "./testUtils": "./src/testUtils.ts", + "./package.json": "./package.json" + }, "main": "src/index.ts", "types": "src/index.ts", + "typesVersions": { + "*": { + "testUtils": [ + "src/testUtils.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "files": [ "dist" ], diff --git a/packages/cli-common/report-testUtils.api.md b/packages/cli-common/report-testUtils.api.md new file mode 100644 index 0000000000..012803d1fb --- /dev/null +++ b/packages/cli-common/report-testUtils.api.md @@ -0,0 +1,23 @@ +## API Report File for "@backstage/cli-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +// @public +export function overrideTargetPaths( + dirOrOptions: string | OverrideTargetPathsOptions, +): TargetPathsOverride; + +// @public +export interface OverrideTargetPathsOptions { + dir: string; + rootDir?: string; +} + +// @public +export interface TargetPathsOverride { + restore(): void; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/cli-common/report.api.md b/packages/cli-common/report.api.md index 96475c6bd1..ba649cacc9 100644 --- a/packages/cli-common/report.api.md +++ b/packages/cli-common/report.api.md @@ -16,17 +16,27 @@ export function bootstrapEnvProxyAgents(): void; // @public export class ExitCodeError extends CustomErrorBase { constructor(code: number, command?: string); - // (undocumented) readonly code: number; } // @public +export function findOwnPaths(searchDir: string): OwnPaths; + +// @public @deprecated export function findPaths(searchDir: string): Paths; // @public export function isChildPath(base: string, path: string): boolean; // @public +export type OwnPaths = { + dir: string; + rootDir: string; + resolve: ResolveFunc; + resolveRoot: ResolveFunc; +}; + +// @public @deprecated export type Paths = { ownDir: string; ownRoot: string; @@ -68,4 +78,15 @@ export function runOutput( args: string[], options?: RunOptions, ): Promise; + +// @public +export type TargetPaths = { + dir: string; + rootDir: string; + resolve: ResolveFunc; + resolveRoot: ResolveFunc; +}; + +// @public +export const targetPaths: TargetPaths; ``` diff --git a/packages/cli-common/src/errors.ts b/packages/cli-common/src/errors.ts index 07664d2ffb..c684ac68d5 100644 --- a/packages/cli-common/src/errors.ts +++ b/packages/cli-common/src/errors.ts @@ -21,6 +21,7 @@ import { CustomErrorBase } from '@backstage/errors'; * @public */ export class ExitCodeError extends CustomErrorBase { + /** The exit code of the child process. */ readonly code: number; constructor(code: number, command?: string) { diff --git a/packages/cli-common/src/index.ts b/packages/cli-common/src/index.ts index d11601b044..e49eac0ee0 100644 --- a/packages/cli-common/src/index.ts +++ b/packages/cli-common/src/index.ts @@ -20,9 +20,9 @@ * @packageDocumentation */ -export { findPaths, BACKSTAGE_JSON } from './paths'; +export { findPaths, findOwnPaths, targetPaths, BACKSTAGE_JSON } from './paths'; export { isChildPath } from './isChildPath'; -export type { Paths, ResolveFunc } from './paths'; +export type { Paths, TargetPaths, OwnPaths, ResolveFunc } from './paths'; export { bootstrapEnvProxyAgents } from './proxyBootstrap'; export { run, diff --git a/packages/cli-common/src/paths.ts b/packages/cli-common/src/paths.ts index 5da2d596a4..1cd84d4f5b 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -25,35 +25,61 @@ import { dirname, resolve as resolvePath } from 'node:path'; */ export type ResolveFunc = (...paths: string[]) => string; +/** + * Resolved paths relative to the target project, based on `process.cwd()`. + * Lazily initialized on first property access. Re-resolves automatically + * when `process.cwd()` changes. + * + * @public + */ +export type TargetPaths = { + /** The target package directory. */ + dir: string; + + /** The target monorepo root directory. */ + rootDir: string; + + /** Resolve a path relative to the target package directory. */ + resolve: ResolveFunc; + + /** Resolve a path relative to the target repo root. */ + resolveRoot: ResolveFunc; +}; + +/** + * Resolved paths relative to a specific package in the repository. + * + * @public + */ +export type OwnPaths = { + /** The package root directory. */ + dir: string; + + /** The monorepo root directory containing the package. */ + rootDir: string; + + /** Resolve a path relative to the package root. */ + resolve: ResolveFunc; + + /** Resolve a path relative to the monorepo root containing the package. */ + resolveRoot: ResolveFunc; +}; + /** * Common paths and resolve functions used by the cli. * Currently assumes it is being executed within a monorepo. * * @public + * @deprecated Use {@link targetPaths} and {@link findOwnPaths} instead. */ export type Paths = { - // Root dir of the cli itself, containing package.json ownDir: string; - - // Monorepo root dir of the cli itself. Only accessible when running inside Backstage repo. ownRoot: string; - - // The location of the app that the cli is being executed in targetDir: string; - - // The monorepo root package of the app that the cli is being executed in. targetRoot: string; - - // Resolve a path relative to own repo resolveOwn: ResolveFunc; - - // Resolve a path relative to own monorepo root. Only accessible when running inside Backstage repo. resolveOwnRoot: ResolveFunc; - - // Resolve a path relative to the app resolveTarget: ResolveFunc; - - // Resolve a path relative to the app repo root resolveTargetRoot: ResolveFunc; }; @@ -84,18 +110,7 @@ export function findRootPath( ); } -// Finds the root of a given package -export function findOwnDir(searchDir: string) { - const path = findRootPath(searchDir, () => true); - if (!path) { - throw new Error( - `No package.json found while searching for package root of ${searchDir}`, - ); - } - return path; -} - -// Finds the root of the monorepo that the package exists in. Only accessible when running inside Backstage repo. +// Finds the root of the monorepo that the package exists in. export function findOwnRootDir(ownDir: string) { const isLocal = fs.existsSync(resolvePath(ownDir, 'src')); if (!isLocal) { @@ -107,64 +122,209 @@ export function findOwnRootDir(ownDir: string) { return resolvePath(ownDir, '../..'); } +// Hierarchical directory cache shared across all OwnPathsImpl instances. +// When we resolve a searchDir to its package root, we also cache every +// intermediate directory, so sibling directories share work. +const dirCache = new Map(); + +class OwnPathsImpl implements OwnPaths { + static #instanceCache = new Map(); + + static find(searchDir: string): OwnPathsImpl { + const dir = OwnPathsImpl.findDir(searchDir); + let instance = OwnPathsImpl.#instanceCache.get(dir); + if (!instance) { + instance = new OwnPathsImpl(dir); + OwnPathsImpl.#instanceCache.set(dir, instance); + } + return instance; + } + + static findDir(searchDir: string): string { + const visited: string[] = []; + let dir = searchDir; + + for (let i = 0; i < 1000; i++) { + const cached = dirCache.get(dir); + if (cached !== undefined) { + for (const d of visited) { + dirCache.set(d, cached); + } + return cached; + } + + visited.push(dir); + + if (fs.existsSync(resolvePath(dir, 'package.json'))) { + for (const d of visited) { + dirCache.set(d, dir); + } + return dir; + } + + const newDir = dirname(dir); + if (newDir === dir) { + break; + } + dir = newDir; + } + + throw new Error( + `No package.json found while searching for package root of ${searchDir}`, + ); + } + + #dir: string; + #rootDir: string | undefined; + + private constructor(dir: string) { + this.#dir = dir; + } + + get dir(): string { + return this.#dir; + } + + get rootDir(): string { + this.#rootDir ??= findOwnRootDir(this.#dir); + return this.#rootDir; + } + + resolve = (...paths: string[]): string => { + return resolvePath(this.#dir, ...paths); + }; + + resolveRoot = (...paths: string[]): string => { + return resolvePath(this.rootDir, ...paths); + }; +} + +// Finds the root of a given package +export function findOwnDir(searchDir: string) { + return OwnPathsImpl.findDir(searchDir); +} + +// Used by the test utility in testUtils.ts to override targetPaths +export let targetPathsOverride: TargetPaths | undefined; + +/** @internal */ +export function setTargetPathsOverride(override: TargetPaths | undefined) { + targetPathsOverride = override; +} + +class TargetPathsImpl implements TargetPaths { + #cwd: string | undefined; + #dir: string | undefined; + #rootDir: string | undefined; + + get dir(): string { + if (targetPathsOverride) { + return targetPathsOverride.dir; + } + const cwd = process.cwd(); + if (this.#dir !== undefined && this.#cwd === cwd) { + return this.#dir; + } + this.#cwd = cwd; + this.#rootDir = undefined; + // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency + this.#dir = fs + .realpathSync(cwd) + .replace(/^[a-z]:/, str => str.toLocaleUpperCase('en-US')); + return this.#dir; + } + + get rootDir(): string { + if (targetPathsOverride) { + return targetPathsOverride.rootDir; + } + // Access dir first to ensure cwd is fresh, which also invalidates rootDir on cwd change + const dir = this.dir; + if (this.#rootDir !== undefined) { + return this.#rootDir; + } + // Lazy init to only crash commands that require a monorepo when we're not in one + this.#rootDir = + findRootPath(dir, path => { + try { + const content = fs.readFileSync(path, 'utf8'); + const data = JSON.parse(content); + return Boolean(data.workspaces); + } catch (error) { + throw new Error( + `Failed to parse package.json file while searching for root, ${error}`, + ); + } + }) ?? dir; + return this.#rootDir; + } + + resolve = (...paths: string[]): string => { + if (targetPathsOverride) { + return targetPathsOverride.resolve(...paths); + } + return resolvePath(this.dir, ...paths); + }; + + resolveRoot = (...paths: string[]): string => { + if (targetPathsOverride) { + return targetPathsOverride.resolveRoot(...paths); + } + return resolvePath(this.rootDir, ...paths); + }; +} + +/** + * Lazily resolved paths relative to the target project. Import this directly + * for cwd-based path resolution without needing `__dirname`. + * + * @public + */ +export const targetPaths: TargetPaths = new TargetPathsImpl(); + +/** + * Find paths relative to the package that the calling code lives in. + * + * Results are cached per package root, and the package root lookup uses a + * hierarchical directory cache so that multiple calls from different + * subdirectories within the same package share work. + * + * @public + */ +export function findOwnPaths(searchDir: string): OwnPaths { + return OwnPathsImpl.find(searchDir); +} + /** * Find paths related to a package and its execution context. * * @public + * @deprecated Use {@link targetPaths} for cwd-based paths and + * {@link findOwnPaths} for package-relative paths instead. + * * @example * * const paths = findPaths(__dirname) */ export function findPaths(searchDir: string): Paths { - const ownDir = findOwnDir(searchDir); - // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency - const targetDir = fs - .realpathSync(process.cwd()) - .replace(/^[a-z]:/, str => str.toLocaleUpperCase('en-US')); - - // Lazy load this as it will throw an error if we're not inside the Backstage repo. - let ownRoot = ''; - const getOwnRoot = () => { - if (!ownRoot) { - ownRoot = findOwnRootDir(ownDir); - } - return ownRoot; - }; - - // We're not always running in a monorepo, so we lazy init this to only crash commands - // that require a monorepo when we're not in one. - let targetRoot = ''; - const getTargetRoot = () => { - if (!targetRoot) { - targetRoot = - findRootPath(targetDir, path => { - try { - const content = fs.readFileSync(path, 'utf8'); - const data = JSON.parse(content); - return Boolean(data.workspaces); - } catch (error) { - throw new Error( - `Failed to parse package.json file while searching for root, ${error}`, - ); - } - }) ?? targetDir; // We didn't find any root package.json, assume we're not in a monorepo - } - return targetRoot; - }; - + const own = findOwnPaths(searchDir); return { - ownDir, + get ownDir() { + return own.dir; + }, get ownRoot() { - return getOwnRoot(); + return own.rootDir; + }, + get targetDir() { + return targetPaths.dir; }, - targetDir, get targetRoot() { - return getTargetRoot(); + return targetPaths.rootDir; }, - resolveOwn: (...paths) => resolvePath(ownDir, ...paths), - resolveOwnRoot: (...paths) => resolvePath(getOwnRoot(), ...paths), - resolveTarget: (...paths) => resolvePath(targetDir, ...paths), - resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), + resolveOwn: own.resolve, + resolveOwnRoot: own.resolveRoot, + resolveTarget: targetPaths.resolve, + resolveTargetRoot: targetPaths.resolveRoot, }; } diff --git a/packages/cli-common/src/testUtils.ts b/packages/cli-common/src/testUtils.ts new file mode 100644 index 0000000000..87c42c469e --- /dev/null +++ b/packages/cli-common/src/testUtils.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2025 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 { resolve as resolvePath } from 'node:path'; +import { setTargetPathsOverride } from './paths'; + +/** + * Options for {@link overrideTargetPaths}. + * + * @public + */ +export interface OverrideTargetPathsOptions { + /** The target package directory. */ + dir: string; + /** The target monorepo root directory. Defaults to `dir` if not provided. */ + rootDir?: string; +} + +/** + * Return value of {@link overrideTargetPaths}. + * + * @public + */ +export interface TargetPathsOverride { + /** Restores `targetPaths` to its normal behavior. */ + restore(): void; +} + +/** + * Overrides the `targetPaths` singleton to resolve from the given directory + * instead of `process.cwd()`. + * + * When called with a string, that value is used as both `dir` and `rootDir`. + * Pass an options object to set them independently. + * + * Calling `restore()` on the return value reverts to normal behavior. + * Restoration is only needed if you want to change the override within a + * test file; each Jest worker starts with a clean module state. + * + * @public + */ +export function overrideTargetPaths( + dirOrOptions: string | OverrideTargetPathsOptions, +): TargetPathsOverride { + const { dir, rootDir } = + typeof dirOrOptions === 'string' + ? { dir: dirOrOptions, rootDir: dirOrOptions } + : { + dir: dirOrOptions.dir, + rootDir: dirOrOptions.rootDir ?? dirOrOptions.dir, + }; + + setTargetPathsOverride({ + dir, + rootDir, + resolve: (...paths: string[]) => resolvePath(dir, ...paths), + resolveRoot: (...paths: string[]) => resolvePath(rootDir, ...paths), + }); + + return { + restore() { + setTargetPathsOverride(undefined); + }, + }; +} diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index b960abfbac..074ba4097c 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/cli-node +## 0.2.19-next.0 + +### Patch Changes + +- 06c2015: Added `runConcurrentTasks` and `runWorkerQueueThreads` utilities, moved from the `@backstage/cli` internal code. +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.2.18 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index a4629c3de2..7d198f0a3f 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index 55d2443643..b3d8fe5641 100644 --- a/packages/cli-node/report.api.md +++ b/packages/cli-node/report.api.md @@ -86,6 +86,13 @@ export interface BackstagePackageJson { version: string; } +// @public +export type ConcurrentTasksOptions = { + concurrencyFactor?: number; + items: Iterable; + worker: (item: TItem) => Promise; +}; + // @public export class GitUtils { static listChangedFiles(ref: string): Promise; @@ -200,4 +207,27 @@ export class PackageRoles { static getRoleFromPackage(pkgJson: unknown): PackageRole | undefined; static getRoleInfo(role: string): PackageRoleInfo; } + +// @public +export function runConcurrentTasks( + options: ConcurrentTasksOptions, +): Promise; + +// @public +export function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, +): Promise<{ + results: TResult[]; +}>; + +// @public +export type WorkerQueueThreadsOptions = { + items: Iterable; + workerFactory: ( + context: TContext, + ) => + | ((item: TItem) => Promise) + | Promise<(item: TItem) => Promise>; + context?: TContext; +}; ``` diff --git a/packages/cli-node/src/concurrency/concurrency.ts b/packages/cli-node/src/concurrency/concurrency.ts new file mode 100644 index 0000000000..fa46f132a0 --- /dev/null +++ b/packages/cli-node/src/concurrency/concurrency.ts @@ -0,0 +1,70 @@ +/* + * 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 os from 'node:os'; + +const defaultConcurrency = Math.max(Math.ceil(os.cpus().length / 2), 1); + +const CONCURRENCY_ENV_VAR = 'BACKSTAGE_CLI_CONCURRENCY'; +const DEPRECATED_CONCURRENCY_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; + +type ConcurrencyOption = boolean | string | number | null | undefined; + +function parseConcurrencyOption(value: ConcurrencyOption): number { + if (value === undefined || value === null) { + return defaultConcurrency; + } else if (typeof value === 'boolean') { + return value ? defaultConcurrency : 1; + } else if (typeof value === 'number' && Number.isInteger(value)) { + if (value < 1) { + return 1; + } + return value; + } else if (typeof value === 'string') { + if (value === 'true') { + return parseConcurrencyOption(true); + } else if (value === 'false') { + return parseConcurrencyOption(false); + } + const parsed = Number(value); + if (Number.isInteger(parsed)) { + return parseConcurrencyOption(parsed); + } + } + + throw Error( + `Concurrency option value '${value}' is not a boolean or integer`, + ); +} + +let hasWarnedDeprecation = false; + +/** @internal */ +export function getEnvironmentConcurrency() { + if (process.env[CONCURRENCY_ENV_VAR] !== undefined) { + return parseConcurrencyOption(process.env[CONCURRENCY_ENV_VAR]); + } + if (process.env[DEPRECATED_CONCURRENCY_ENV_VAR] !== undefined) { + if (!hasWarnedDeprecation) { + hasWarnedDeprecation = true; + console.warn( + `The ${DEPRECATED_CONCURRENCY_ENV_VAR} environment variable is deprecated, use ${CONCURRENCY_ENV_VAR} instead`, + ); + } + return parseConcurrencyOption(process.env[DEPRECATED_CONCURRENCY_ENV_VAR]); + } + return defaultConcurrency; +} diff --git a/packages/cli-node/src/paths.ts b/packages/cli-node/src/concurrency/index.ts similarity index 69% rename from packages/cli-node/src/paths.ts rename to packages/cli-node/src/concurrency/index.ts index 2c658c27b3..3ff4067a20 100644 --- a/packages/cli-node/src/paths.ts +++ b/packages/cli-node/src/concurrency/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); +export type { ConcurrentTasksOptions } from './runConcurrentTasks'; +export { runConcurrentTasks } from './runConcurrentTasks'; +export type { WorkerQueueThreadsOptions } from './runWorkerQueueThreads'; +export { runWorkerQueueThreads } from './runWorkerQueueThreads'; diff --git a/packages/cli-node/src/concurrency/runConcurrentTasks.test.ts b/packages/cli-node/src/concurrency/runConcurrentTasks.test.ts new file mode 100644 index 0000000000..382a85d297 --- /dev/null +++ b/packages/cli-node/src/concurrency/runConcurrentTasks.test.ts @@ -0,0 +1,144 @@ +/* + * 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 { runConcurrentTasks } from './runConcurrentTasks'; + +describe('runConcurrentTasks', () => { + afterEach(() => { + delete process.env.BACKSTAGE_CLI_CONCURRENCY; + }); + + it('executes work in parallel', async () => { + const started = new Array(); + const done = new Array(); + const waiting = new Array<() => void>(); + + process.env.BACKSTAGE_CLI_CONCURRENCY = '4'; + const work = runConcurrentTasks({ + items: [0, 1, 2, 3, 4], + concurrencyFactor: 0.5, // 2 at a time + worker: async item => { + started.push(item); + await new Promise(resolve => { + waiting[item] = resolve; + }); + done.push(item); + }, + }); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1]); + expect(done).toEqual([]); + waiting[0](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1, 2]); + expect(done).toEqual([0]); + waiting[1](); + waiting[2](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1, 2, 3, 4]); + expect(done).toEqual([0, 1, 2]); + waiting[3](); + waiting[4](); + + await work; + expect(done).toEqual([0, 1, 2, 3, 4]); + }); + + it('executes work sequentially', async () => { + const started = new Array(); + const done = new Array(); + const waiting = new Array<() => void>(); + + const work = runConcurrentTasks({ + items: [0, 1, 2, 3, 4], + concurrencyFactor: 0, // 1 at a time + worker: async item => { + started.push(item); + await new Promise(resolve => { + waiting[item] = resolve; + }); + done.push(item); + }, + }); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0]); + expect(done).toEqual([]); + waiting[0](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1]); + expect(done).toEqual([0]); + waiting[1](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1, 2]); + waiting[2](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1, 2, 3]); + waiting[3](); + + await new Promise(resolve => setTimeout(resolve)); + expect(started).toEqual([0, 1, 2, 3, 4]); + waiting[4](); + + await work; + expect(done).toEqual([0, 1, 2, 3, 4]); + }); + + it('returns void', async () => { + const result = await runConcurrentTasks({ + items: [1, 2, 3], + worker: async () => {}, + }); + expect(result).toBeUndefined(); + }); + + it('defaults to environment concurrency', async () => { + const started = new Array(); + process.env.BACKSTAGE_CLI_CONCURRENCY = '2'; + + await runConcurrentTasks({ + items: [0, 1], + worker: async item => { + started.push(item); + }, + }); + + expect(started).toEqual([0, 1]); + }); + + it('supports the deprecated BACKSTAGE_CLI_BUILD_PARALLEL with a warning', async () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + + process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '2'; + await runConcurrentTasks({ + items: [0, 1], + worker: async () => {}, + }); + + expect(warnSpy).toHaveBeenCalledWith( + 'The BACKSTAGE_CLI_BUILD_PARALLEL environment variable is deprecated, use BACKSTAGE_CLI_CONCURRENCY instead', + ); + + delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; + warnSpy.mockRestore(); + }); +}); diff --git a/packages/cli-node/src/concurrency/runConcurrentTasks.ts b/packages/cli-node/src/concurrency/runConcurrentTasks.ts new file mode 100644 index 0000000000..1695f25403 --- /dev/null +++ b/packages/cli-node/src/concurrency/runConcurrentTasks.ts @@ -0,0 +1,62 @@ +/* + * 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 { getEnvironmentConcurrency } from './concurrency'; + +/** + * Options for {@link runConcurrentTasks}. + * + * @public + */ +export type ConcurrentTasksOptions = { + /** + * Decides the number of concurrent workers by multiplying + * this with the configured concurrency. + * + * Defaults to 1. + */ + concurrencyFactor?: number; + items: Iterable; + worker: (item: TItem) => Promise; +}; + +/** + * Runs items through a worker function concurrently across multiple async workers. + * + * @public + */ +export async function runConcurrentTasks( + options: ConcurrentTasksOptions, +): Promise { + const { concurrencyFactor = 1, items, worker } = options; + const concurrency = getEnvironmentConcurrency(); + + const sharedIterator = items[Symbol.iterator](); + const sharedIterable = { + [Symbol.iterator]: () => sharedIterator, + }; + + const workerCount = Math.max(Math.floor(concurrencyFactor * concurrency), 1); + await Promise.all( + Array(workerCount) + .fill(0) + .map(async () => { + for (const value of sharedIterable) { + await worker(value); + } + }), + ); +} diff --git a/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts b/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts new file mode 100644 index 0000000000..5dd2cda438 --- /dev/null +++ b/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { runWorkerQueueThreads } from './runWorkerQueueThreads'; + +describe('runWorkerQueueThreads', () => { + it('should execute work in parallel', async () => { + const sharedData = new SharedArrayBuffer(10); + const sharedView = new Uint8Array(sharedData); + + const { results } = await runWorkerQueueThreads({ + context: sharedData, + items: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + workerFactory: (data: SharedArrayBuffer) => { + const view = new Uint8Array(data); + + return async (i: number) => { + view[i] = 10 + i; + return 20 + i; + }; + }, + }); + + expect(Array.from(sharedView)).toEqual([ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + ]); + expect(results).toEqual([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]); + }); +}); diff --git a/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts new file mode 100644 index 0000000000..2d2a3b37e4 --- /dev/null +++ b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts @@ -0,0 +1,175 @@ +/* + * 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 { ErrorLike } from '@backstage/errors'; +import { Worker } from 'node:worker_threads'; +import { getEnvironmentConcurrency } from './concurrency'; + +type WorkerThreadMessage = + | { + type: 'done'; + } + | { + type: 'item'; + index: number; + item: unknown; + } + | { + type: 'start'; + } + | { + type: 'result'; + index: number; + result: unknown; + } + | { + type: 'error'; + error: ErrorLike; + }; + +/** + * Options for {@link runWorkerQueueThreads}. + * + * @public + */ +export type WorkerQueueThreadsOptions = { + /** The items to process */ + items: Iterable; + /** + * A function that will be called within each worker thread at startup, + * which should return the worker function that will be called for each item. + * + * This function must be defined as an arrow function or using the + * function keyword, and must be entirely self contained, not referencing + * any variables outside of its scope. This is because the function source + * is stringified and evaluated in the worker thread. + * + * To pass data to the worker, use the `context` option and `items`, but + * note that they are both copied by value into the worker thread, except for + * types that are explicitly shareable across threads, such as `SharedArrayBuffer`. + */ + workerFactory: ( + context: TContext, + ) => + | ((item: TItem) => Promise) + | Promise<(item: TItem) => Promise>; + /** Context data supplied to each worker factory */ + context?: TContext; +}; + +/** + * Spawns one or more worker threads using the `worker_threads` module. + * Each thread processes one item at a time from the provided `options.items`. + * + * @public + */ +export async function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, +): Promise<{ results: TResult[] }> { + const items = Array.from(options.items); + const workerFactory = options.workerFactory; + const workerData = options.context; + const threadCount = Math.min(getEnvironmentConcurrency(), items.length); + + const iterator = items[Symbol.iterator](); + const results = new Array(); + let itemIndex = 0; + + await Promise.all( + Array(threadCount) + .fill(0) + .map(async () => { + const thread = new Worker(`(${workerQueueThread})(${workerFactory})`, { + eval: true, + workerData, + }); + + return new Promise((resolve, reject) => { + thread.on('message', (message: WorkerThreadMessage) => { + if (message.type === 'start' || message.type === 'result') { + if (message.type === 'result') { + results[message.index] = message.result as TResult; + } + const { value, done } = iterator.next(); + if (done) { + thread.postMessage({ type: 'done' }); + } else { + thread.postMessage({ + type: 'item', + index: itemIndex, + item: value, + }); + itemIndex += 1; + } + } else if (message.type === 'error') { + const error = new Error(message.error.message); + error.name = message.error.name; + error.stack = message.error.stack; + reject(error); + } + }); + + thread.on('error', reject); + thread.on('exit', (code: number) => { + if (code !== 0) { + reject(new Error(`Worker thread exited with code ${code}`)); + } else { + resolve(); + } + }); + }); + }), + ); + + return { results }; +} + +/* istanbul ignore next */ +function workerQueueThread( + workerFuncFactory: ( + data: unknown, + ) => Promise<(item: unknown) => Promise>, +) { + const { parentPort, workerData } = require('node:worker_threads'); + + Promise.resolve() + .then(() => workerFuncFactory(workerData)) + .then( + workerFunc => { + parentPort.on('message', async (message: WorkerThreadMessage) => { + if (message.type === 'done') { + parentPort.close(); + return; + } + if (message.type === 'item') { + try { + const result = await workerFunc(message.item); + parentPort.postMessage({ + type: 'result', + index: message.index, + result, + }); + } catch (error) { + parentPort.postMessage({ type: 'error', error }); + } + } + }); + + parentPort.postMessage({ type: 'start' }); + }, + error => parentPort.postMessage({ type: 'error', error }), + ); +} diff --git a/packages/cli-node/src/git/GitUtils.ts b/packages/cli-node/src/git/GitUtils.ts index 7edb3581d6..f2350be309 100644 --- a/packages/cli-node/src/git/GitUtils.ts +++ b/packages/cli-node/src/git/GitUtils.ts @@ -15,7 +15,7 @@ */ import { assertError, ForwardedError } from '@backstage/errors'; -import { paths } from '../paths'; +import { targetPaths } from '@backstage/cli-common'; import { runOutput } from '@backstage/cli-common'; /** @@ -24,7 +24,7 @@ import { runOutput } from '@backstage/cli-common'; export async function runGit(...args: string[]) { try { const stdout = await runOutput(['git', ...args], { - cwd: paths.targetRoot, + cwd: targetPaths.rootDir, }); return stdout.trim().split(/\r\n|\r|\n/); } catch (error) { @@ -88,7 +88,7 @@ export class GitUtils { } const stdout = await runOutput(['git', 'show', `${showRef}:${path}`], { - cwd: paths.targetRoot, + cwd: targetPaths.rootDir, }); return stdout; } diff --git a/packages/cli-node/src/index.ts b/packages/cli-node/src/index.ts index 1d3f3ec2ed..5540666a05 100644 --- a/packages/cli-node/src/index.ts +++ b/packages/cli-node/src/index.ts @@ -22,4 +22,5 @@ export * from './git'; export * from './monorepo'; +export * from './concurrency'; export * from './roles'; diff --git a/packages/cli-node/src/monorepo/PackageGraph.test.ts b/packages/cli-node/src/monorepo/PackageGraph.test.ts index d1a0cce649..51d8f7b7be 100644 --- a/packages/cli-node/src/monorepo/PackageGraph.test.ts +++ b/packages/cli-node/src/monorepo/PackageGraph.test.ts @@ -14,21 +14,16 @@ * limitations under the License. */ -import { resolve as resolvePath } from 'node:path'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from './PackageGraph'; import { Lockfile } from './Lockfile'; import { GitUtils } from '../git'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; const mockListChangedFiles = jest.spyOn(GitUtils, 'listChangedFiles'); const mockReadFileAtRef = jest.spyOn(GitUtils, 'readFileAtRef'); -jest.mock('../paths', () => ({ - paths: { - targetRoot: '/', - resolveTargetRoot: (...paths: string[]) => resolvePath('/', ...paths), - }, -})); +overrideTargetPaths('/'); const testPackages = [ { diff --git a/packages/cli-node/src/monorepo/PackageGraph.ts b/packages/cli-node/src/monorepo/PackageGraph.ts index 6d3da7cf82..9d1745c7c5 100644 --- a/packages/cli-node/src/monorepo/PackageGraph.ts +++ b/packages/cli-node/src/monorepo/PackageGraph.ts @@ -16,7 +16,7 @@ import path from 'node:path'; import { getPackages, Package } from '@manypkg/get-packages'; -import { paths } from '../paths'; +import { targetPaths } from '@backstage/cli-common'; import { PackageRole } from '../roles'; import { GitUtils } from '../git'; import { Lockfile } from './Lockfile'; @@ -192,7 +192,7 @@ export class PackageGraph extends Map { * Lists all local packages in a monorepo. */ static async listTargetPackages(): Promise { - const { packages } = await getPackages(paths.targetDir); + const { packages } = await getPackages(targetPaths.dir); return packages as BackstagePackage[]; } @@ -332,7 +332,7 @@ export class PackageGraph extends Map { Array.from(this.values()).map(pkg => [ // relative from root, convert to posix, and add a / at the end path - .relative(paths.targetRoot, pkg.dir) + .relative(targetPaths.rootDir, pkg.dir) .split(path.sep) .join(path.posix.sep) + path.posix.sep, pkg, @@ -374,7 +374,7 @@ export class PackageGraph extends Map { let otherLockfile: Lockfile; try { thisLockfile = await Lockfile.load( - paths.resolveTargetRoot('yarn.lock'), + targetPaths.resolveRoot('yarn.lock'), ); otherLockfile = Lockfile.parse( await GitUtils.readFileAtRef('yarn.lock', options.ref), diff --git a/packages/cli-node/src/monorepo/isMonoRepo.ts b/packages/cli-node/src/monorepo/isMonoRepo.ts index c58b3d00ce..ca6b209a7a 100644 --- a/packages/cli-node/src/monorepo/isMonoRepo.ts +++ b/packages/cli-node/src/monorepo/isMonoRepo.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths } from '../paths'; +import { targetPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; /** @@ -26,7 +26,7 @@ import fs from 'fs-extra'; * @public */ export async function isMonoRepo(): Promise { - const rootPackageJsonPath = paths.resolveTargetRoot('package.json'); + const rootPackageJsonPath = targetPaths.resolveRoot('package.json'); try { const pkg = await fs.readJson(rootPackageJsonPath); return Boolean(pkg?.workspaces); diff --git a/packages/cli-node/src/monorepo/isMonorepo.test.ts b/packages/cli-node/src/monorepo/isMonorepo.test.ts index de0dae0893..e13f9a8784 100644 --- a/packages/cli-node/src/monorepo/isMonorepo.test.ts +++ b/packages/cli-node/src/monorepo/isMonorepo.test.ts @@ -16,12 +16,10 @@ import { isMonoRepo } from './isMonoRepo'; import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; const mockDir = createMockDirectory(); - -jest.mock('../paths', () => ({ - paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, -})); +overrideTargetPaths(mockDir.path); describe('isMonoRepo', () => { it('should detect a monorepo', async () => { diff --git a/packages/cli-node/src/pacman/PackageManager.test.ts b/packages/cli-node/src/pacman/PackageManager.test.ts index f704610ab2..4f7446901f 100644 --- a/packages/cli-node/src/pacman/PackageManager.test.ts +++ b/packages/cli-node/src/pacman/PackageManager.test.ts @@ -15,16 +15,13 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { detectPackageManager } from './PackageManager'; import { Yarn } from './yarn'; import { withLogCollector } from '@backstage/test-utils'; const mockDir = createMockDirectory(); - -jest.mock('../paths', () => ({ - ...jest.requireActual('../paths'), - paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, -})); +overrideTargetPaths(mockDir.path); const mockYarnCreate = jest.spyOn(Yarn, 'create'); diff --git a/packages/cli-node/src/pacman/PackageManager.ts b/packages/cli-node/src/pacman/PackageManager.ts index 0029652544..852ccc1288 100644 --- a/packages/cli-node/src/pacman/PackageManager.ts +++ b/packages/cli-node/src/pacman/PackageManager.ts @@ -16,7 +16,7 @@ import { Yarn } from './yarn'; import { Lockfile } from './Lockfile'; -import { paths } from '../paths'; +import { targetPaths } from '@backstage/cli-common'; import { RunOptions } from '@backstage/cli-common'; import fs from 'fs-extra'; @@ -85,7 +85,7 @@ export interface PackageManager { */ export async function detectPackageManager(): Promise { const hasYarnLockfile = await fileExists( - paths.resolveTargetRoot('yarn.lock'), + targetPaths.resolveRoot('yarn.lock'), ); if (hasYarnLockfile) { return await Yarn.create(); @@ -93,7 +93,7 @@ export async function detectPackageManager(): Promise { try { const packageJson = await fs.readJson( - paths.resolveTargetRoot('package.json'), + targetPaths.resolveRoot('package.json'), ); if (packageJson.workspaces) { // technically this could be NPM as well diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0fe123854c..6ccd21fb31 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/cli +## 0.35.5-next.0 + +### Patch Changes + +- 246877a: Updated dependency `bfj` to `^9.0.2`. +- bba2e49: Internal refactor to use new concurrency utilities from `@backstage/cli-node`. +- fd50cb3: Added `translations export` and `translations import` commands for managing translation files. + + The `translations export` command discovers all `TranslationRef` definitions across frontend plugin dependencies and exports their default messages as JSON files. The `translations import` command generates `TranslationResource` wiring code from translated JSON files, ready to be plugged into the app. + + Both commands support a `--pattern` option for controlling the message file layout, for example `--pattern '{lang}/{id}.json'` for language-based directory grouping. + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- 092b41f: Updated dependency `webpack` to `~5.105.0`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/eslint-plugin@0.2.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/module-federation-common@0.1.0 + - @backstage/release-manifests@0.0.13 + - @backstage/types@1.2.2 + ## 0.35.4 ### Patch Changes diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 0948954ff7..ee4b03cbca 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -25,6 +25,7 @@ Commands: new package [command] repo [command] + translations [command] versions:bump versions:migrate ``` @@ -542,6 +543,44 @@ Options: -h, --help ``` +### `backstage-cli translations` + +``` +Usage: backstage-cli translations [options] [command] [command] + +Options: + -h, --help + +Commands: + export + help [command] + import +``` + +### `backstage-cli translations export` + +``` +Usage: + +Options: + --help + --output + --pattern + --version +``` + +### `backstage-cli translations import` + +``` +Usage: + +Options: + --help + --input + --output + --version +``` + ### `backstage-cli versions:bump` ``` diff --git a/packages/cli/package.json b/packages/cli/package.json index 9e1d0b77f0..27a1b92471 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.35.4", + "version": "0.35.5-next.0", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index ece1e413a0..9240ad876c 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -27,5 +27,6 @@ import { CliInitializer } from './wiring/CliInitializer'; initializer.add(import('./modules/migrate')); initializer.add(import('./modules/new')); initializer.add(import('./modules/test')); + initializer.add(import('./modules/translations')); await initializer.run(); })(); diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index a799970b4d..8131a469a4 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../paths'; +import { targetPaths } from '@backstage/cli-common'; const DEFAULT_CACHE_BASE_PATH = 'node_modules/.cache/backstage-cli'; @@ -31,7 +31,7 @@ export class SuccessCache { * location. */ static trimPaths(input: string) { - return input.replaceAll(paths.targetRoot, ''); + return input.replaceAll(targetPaths.rootDir, ''); } constructor(name: string, basePath?: string) { diff --git a/packages/cli/src/lib/parallel.test.ts b/packages/cli/src/lib/parallel.test.ts deleted file mode 100644 index 389e22102b..0000000000 --- a/packages/cli/src/lib/parallel.test.ts +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import os from 'node:os'; -import { - parseParallelismOption, - getEnvironmentParallelism, - runParallelWorkers, - runWorkerQueueThreads, - runWorkerThreads, -} from './parallel'; - -const defaultParallelism = Math.ceil(os.cpus().length / 2); - -describe('parseParallelismOption', () => { - it('coerces false no parallelism', () => { - expect(parseParallelismOption(false)).toBe(1); - expect(parseParallelismOption('false')).toBe(1); - }); - - it('coerces true or undefined to default parallelism', () => { - expect(parseParallelismOption(true)).toBe(defaultParallelism); - expect(parseParallelismOption('true')).toBe(defaultParallelism); - expect(parseParallelismOption(undefined)).toBe(defaultParallelism); - expect(parseParallelismOption(null)).toBe(defaultParallelism); - }); - - it('coerces number string to number', () => { - expect(parseParallelismOption('2')).toBe(2); - }); - - it.each([['on'], [2.5], ['2.5']])('throws error for %p', value => { - expect(() => parseParallelismOption(value as any)).toThrow( - `Parallel option value '${value}' is not a boolean or integer`, - ); - }); -}); - -describe('getEnvironmentParallelism', () => { - it('reads the parallelism setting from the environment', () => { - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '2'; - expect(getEnvironmentParallelism()).toBe(2); - - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'true'; - expect(getEnvironmentParallelism()).toBe(defaultParallelism); - - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'false'; - expect(getEnvironmentParallelism()).toBe(1); - - delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; - expect(getEnvironmentParallelism()).toBe(defaultParallelism); - }); -}); - -describe('runParallelWorkers', () => { - it('executes work in parallel', async () => { - const started = new Array(); - const done = new Array(); - const waiting = new Array<() => void>(); - - const work = runParallelWorkers({ - items: [0, 1, 2, 3, 4], - parallelismSetting: 4, - parallelismFactor: 0.5, // 2 at a time - worker: async item => { - started.push(item); - await new Promise(resolve => { - waiting[item] = resolve; - }); - done.push(item); - }, - }); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1]); - expect(done).toEqual([]); - waiting[0](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1, 2]); - expect(done).toEqual([0]); - waiting[1](); - waiting[2](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1, 2, 3, 4]); - expect(done).toEqual([0, 1, 2]); - waiting[3](); - waiting[4](); - - await work; - expect(done).toEqual([0, 1, 2, 3, 4]); - }); - - it('executes work sequentially', async () => { - const started = new Array(); - const done = new Array(); - const waiting = new Array<() => void>(); - - const work = runParallelWorkers({ - items: [0, 1, 2, 3, 4], - parallelismFactor: 0, // 1 at a time - worker: async item => { - started.push(item); - await new Promise(resolve => { - waiting[item] = resolve; - }); - done.push(item); - }, - }); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0]); - expect(done).toEqual([]); - waiting[0](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1]); - expect(done).toEqual([0]); - waiting[1](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1, 2]); - waiting[2](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1, 2, 3]); - waiting[3](); - - await new Promise(resolve => setTimeout(resolve)); - expect(started).toEqual([0, 1, 2, 3, 4]); - waiting[4](); - - await work; - expect(done).toEqual([0, 1, 2, 3, 4]); - }); -}); - -describe('runWorkerQueueThreads', () => { - it('should execute work in parallel', async () => { - const sharedData = new SharedArrayBuffer(10); - const sharedView = new Uint8Array(sharedData); - - const results = await runWorkerQueueThreads({ - threadCount: 4, - workerData: sharedData, - items: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - workerFactory: data => { - const view = new Uint8Array(data); - - return async (i: number) => { - view[i] = 10 + i; - return 20 + i; - }; - }, - }); - - expect(Array.from(sharedView)).toEqual([ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - ]); - expect(results).toEqual([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]); - }); -}); - -describe('runWorkerThreads', () => { - it('should run a single thread without items', async () => { - const [result] = await runWorkerThreads({ - threadCount: 1, - workerData: 'foo', - worker: async data => `${data}bar`, - }); - - expect(result).toBe('foobar'); - }); - - it('should run multiple threads without items', async () => { - const results = await runWorkerThreads({ - threadCount: 4, - worker: async () => 'foo', - }); - - expect(results).toEqual(['foo', 'foo', 'foo', 'foo']); - }); - - it('should send messages', async () => { - const messages = new Array(); - - await runWorkerThreads({ - threadCount: 2, - worker: async (_data, sendMessage) => { - sendMessage('a'); - await new Promise(resolve => setTimeout(resolve, 10)); - sendMessage('b'); - await new Promise(resolve => setTimeout(resolve, 10)); - sendMessage('c'); - }, - onMessage: (message: string) => messages.push(message), - }); - - expect(messages.sort()).toEqual(['a', 'a', 'b', 'b', 'c', 'c']); - }); -}); diff --git a/packages/cli/src/lib/parallel.ts b/packages/cli/src/lib/parallel.ts deleted file mode 100644 index a4ca5dd13d..0000000000 --- a/packages/cli/src/lib/parallel.ts +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import os from 'node:os'; -import { ErrorLike } from '@backstage/errors'; -import { Worker } from 'node:worker_threads'; - -const defaultParallelism = Math.ceil(os.cpus().length / 2); - -const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; - -export type ParallelismOption = boolean | string | number | null | undefined; - -export function parseParallelismOption(parallel: ParallelismOption): number { - if (parallel === undefined || parallel === null) { - return defaultParallelism; - } else if (typeof parallel === 'boolean') { - return parallel ? defaultParallelism : 1; - } else if (typeof parallel === 'number' && Number.isInteger(parallel)) { - if (parallel < 1) { - return 1; - } - return parallel; - } else if (typeof parallel === 'string') { - if (parallel === 'true') { - return parseParallelismOption(true); - } else if (parallel === 'false') { - return parseParallelismOption(false); - } - const parsed = Number(parallel); - if (Number.isInteger(parsed)) { - return parseParallelismOption(parsed); - } - } - - throw Error( - `Parallel option value '${parallel}' is not a boolean or integer`, - ); -} - -export function getEnvironmentParallelism() { - return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); -} - -type ParallelWorkerOptions = { - /** - * Decides the number of parallel workers by multiplying - * this with the configured parallelism, which defaults to 4. - * - * Defaults to 1. - */ - parallelismFactor?: number; - parallelismSetting?: ParallelismOption; - items: Iterable; - worker: (item: TItem) => Promise; -}; - -export async function runParallelWorkers( - options: ParallelWorkerOptions, -) { - const { parallelismFactor = 1, parallelismSetting, items, worker } = options; - const parallelism = parallelismSetting - ? parseParallelismOption(parallelismSetting) - : getEnvironmentParallelism(); - - const sharedIterator = items[Symbol.iterator](); - const sharedIterable = { - [Symbol.iterator]: () => sharedIterator, - }; - - const workerCount = Math.max(Math.floor(parallelismFactor * parallelism), 1); - return Promise.all( - Array(workerCount) - .fill(0) - .map(async () => { - for (const value of sharedIterable) { - await worker(value); - } - }), - ); -} - -type WorkerThreadMessage = - | { - type: 'done'; - } - | { - type: 'item'; - index: number; - item: unknown; - } - | { - type: 'start'; - } - | { - type: 'result'; - index: number; - result: unknown; - } - | { - type: 'error'; - error: ErrorLike; - } - | { - type: 'message'; - message: unknown; - }; - -export type WorkerQueueThreadsOptions = { - /** The items to process */ - items: Iterable; - /** - * A function that will be called within each worker thread at startup, - * which should return the worker function that will be called for each item. - * - * This function must be defined as an arrow function or using the - * function keyword, and must be entirely self contained, not referencing - * any variables outside of its scope. This is because the function source - * is stringified and evaluated in the worker thread. - * - * To pass data to the worker, use the `workerData` option and `items`, but - * note that they are both copied by value into the worker thread, except for - * types that are explicitly shareable across threads, such as `SharedArrayBuffer`. - */ - workerFactory: ( - data: TData, - ) => - | ((item: TItem) => Promise) - | Promise<(item: TItem) => Promise>; - /** Data supplied to each worker factory */ - workerData?: TData; - /** Number of threads, defaults to half of the number of available CPUs */ - threadCount?: number; -}; - -/** - * Spawns one or more worker threads using the `worker_threads` module. - * Each thread processes one item at a time from the provided `options.items`. - */ -export async function runWorkerQueueThreads( - options: WorkerQueueThreadsOptions, -): Promise { - const items = Array.from(options.items); - const { - workerFactory, - workerData, - threadCount = Math.min(getEnvironmentParallelism(), items.length), - } = options; - - const iterator = items[Symbol.iterator](); - const results = new Array(); - let itemIndex = 0; - - await Promise.all( - Array(threadCount) - .fill(0) - .map(async () => { - const thread = new Worker(`(${workerQueueThread})(${workerFactory})`, { - eval: true, - workerData, - }); - - return new Promise((resolve, reject) => { - thread.on('message', (message: WorkerThreadMessage) => { - if (message.type === 'start' || message.type === 'result') { - if (message.type === 'result') { - results[message.index] = message.result as TResult; - } - const { value, done } = iterator.next(); - if (done) { - thread.postMessage({ type: 'done' }); - } else { - thread.postMessage({ - type: 'item', - index: itemIndex, - item: value, - }); - itemIndex += 1; - } - } else if (message.type === 'error') { - const error = new Error(message.error.message); - error.name = message.error.name; - error.stack = message.error.stack; - reject(error); - } - }); - - thread.on('error', reject); - thread.on('exit', (code: number) => { - if (code !== 0) { - reject(new Error(`Worker thread exited with code ${code}`)); - } else { - resolve(); - } - }); - }); - }), - ); - - return results; -} - -/* istanbul ignore next */ -function workerQueueThread( - workerFuncFactory: ( - data: unknown, - ) => Promise<(item: unknown) => Promise>, -) { - const { parentPort, workerData } = require('node:worker_threads'); - - Promise.resolve() - .then(() => workerFuncFactory(workerData)) - .then( - workerFunc => { - parentPort.on('message', async (message: WorkerThreadMessage) => { - if (message.type === 'done') { - parentPort.close(); - return; - } - if (message.type === 'item') { - try { - const result = await workerFunc(message.item); - parentPort.postMessage({ - type: 'result', - index: message.index, - result, - }); - } catch (error) { - parentPort.postMessage({ type: 'error', error }); - } - } - }); - - parentPort.postMessage({ type: 'start' }); - }, - error => parentPort.postMessage({ type: 'error', error }), - ); -} - -export type WorkerThreadsOptions = { - /** - * A function that is called by each worker thread to produce a result. - * - * This function must be defined as an arrow function or using the - * function keyword, and must be entirely self contained, not referencing - * any variables outside of its scope. This is because the function source - * is stringified and evaluated in the worker thread. - * - * To pass data to the worker, use the `workerData` option, but - * note that they are both copied by value into the worker thread, except for - * types that are explicitly shareable across threads, such as `SharedArrayBuffer`. - */ - worker: ( - data: TData, - sendMessage: (message: TMessage) => void, - ) => Promise; - /** Data supplied to each worker */ - workerData?: TData; - /** Number of threads, defaults to 1 */ - threadCount?: number; - /** An optional handler for messages posted from the worker thread */ - onMessage?: (message: TMessage) => void; -}; - -/** - * Spawns one or more worker threads using the `worker_threads` module. - */ -export async function runWorkerThreads( - options: WorkerThreadsOptions, -): Promise { - const { worker, workerData, threadCount = 1, onMessage } = options; - - return Promise.all( - Array(threadCount) - .fill(0) - .map(async () => { - const thread = new Worker(`(${workerThread})(${worker})`, { - eval: true, - workerData, - }); - - return new Promise((resolve, reject) => { - thread.on('message', (message: WorkerThreadMessage) => { - if (message.type === 'result') { - resolve(message.result as TResult); - } else if (message.type === 'error') { - reject(message.error); - } else if (message.type === 'message') { - onMessage?.(message.message as TMessage); - } - }); - - thread.on('error', reject); - thread.on('exit', (code: number) => { - reject( - new Error(`Unexpected worker thread exit with code ${code}`), - ); - }); - }); - }), - ); -} - -/* istanbul ignore next */ -function workerThread( - workerFunc: ( - data: unknown, - sendMessage: (message: unknown) => void, - ) => Promise, -) { - const { parentPort, workerData } = require('node:worker_threads'); - - const sendMessage = (message: unknown) => { - parentPort.postMessage({ type: 'message', message }); - }; - - workerFunc(workerData, sendMessage).then( - result => { - parentPort.postMessage({ - type: 'result', - index: 0, - result, - }); - }, - error => { - parentPort.postMessage({ type: 'error', error }); - }, - ); -} diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index d8469aee37..e9cc96d988 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -20,11 +20,11 @@ import { } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; import { Project, SourceFile, SyntaxKind, ts, Type } from 'ts-morph'; -import { paths } from './paths'; +import { targetPaths } from '@backstage/cli-common'; export const createTypeDistProject = async () => { return new Project({ - tsConfigFilePath: paths.resolveTargetRoot('tsconfig.json'), + tsConfigFilePath: targetPaths.resolveRoot('tsconfig.json'), skipAddingFilesFromTsConfig: true, }); }; diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index a7a7ca1bdb..aa8556534f 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -16,9 +16,12 @@ import fs from 'fs-extra'; import semver from 'semver'; -import { paths } from './paths'; +import { findOwnPaths } from '@backstage/cli-common'; import { Lockfile } from './versioning'; +/* eslint-disable-next-line no-restricted-syntax */ +const ownPaths = findOwnPaths(__dirname); + /* eslint-disable @backstage/no-relative-monorepo-imports */ /* This is a list of all packages used by the templates. If dependencies are added or removed, @@ -82,12 +85,12 @@ export const packageVersions: Record = { }; export function findVersion() { - const pkgContent = fs.readFileSync(paths.resolveOwn('package.json'), 'utf8'); + const pkgContent = fs.readFileSync(ownPaths.resolve('package.json'), 'utf8'); return JSON.parse(pkgContent).version; } export const version = findVersion(); -export const isDev = fs.pathExistsSync(paths.resolveOwn('src')); +export const isDev = fs.pathExistsSync(ownPaths.resolve('src')); export function createPackageVersionProvider( lockfile?: Lockfile, diff --git a/packages/cli/src/lib/yarnPlugin.test.ts b/packages/cli/src/lib/yarnPlugin.test.ts index d5c865e1c4..a07c2a2ac6 100644 --- a/packages/cli/src/lib/yarnPlugin.test.ts +++ b/packages/cli/src/lib/yarnPlugin.test.ts @@ -15,17 +15,11 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { getHasYarnPlugin } from './yarnPlugin'; const mockDir = createMockDirectory(); - -jest.mock('./paths', () => ({ - paths: { - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); - }, - }, -})); +overrideTargetPaths(mockDir.path); describe('getHasYarnPlugin', () => { beforeEach(() => { diff --git a/packages/cli/src/lib/yarnPlugin.ts b/packages/cli/src/lib/yarnPlugin.ts index 5ad49b2524..0390345651 100644 --- a/packages/cli/src/lib/yarnPlugin.ts +++ b/packages/cli/src/lib/yarnPlugin.ts @@ -17,7 +17,7 @@ import fs from 'fs-extra'; import yaml from 'yaml'; import z from 'zod'; -import { paths } from './paths'; +import { targetPaths } from '@backstage/cli-common'; const yarnRcSchema = z.object({ plugins: z @@ -35,7 +35,7 @@ const yarnRcSchema = z.object({ * @returns Promise - true if the plugin is installed, false otherwise */ export async function getHasYarnPlugin(): Promise { - const yarnRcPath = paths.resolveTargetRoot('.yarnrc.yml'); + const yarnRcPath = targetPaths.resolveRoot('.yarnrc.yml'); const yarnRcContent = await fs.readFile(yarnRcPath, 'utf-8').catch(e => { if (e.code === 'ENOENT') { // gracefully continue in case the file doesn't exist diff --git a/packages/cli/src/modules/build/commands/package/build/command.ts b/packages/cli/src/modules/build/commands/package/build/command.ts index 0882cfcf4f..944be832f0 100644 --- a/packages/cli/src/modules/build/commands/package/build/command.ts +++ b/packages/cli/src/modules/build/commands/package/build/command.ts @@ -23,7 +23,8 @@ import { PackageGraph, PackageRoles, } from '@backstage/cli-node'; -import { paths } from '../../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { buildFrontend } from '../../../lib/buildFrontend'; import { buildBackend } from '../../../lib/buildBackend'; import { isValidUrl } from '../../../lib/urls'; @@ -41,19 +42,19 @@ export async function command(opts: OptionValues): Promise { if (isValidUrl(arg)) { return arg; } - return paths.resolveTarget(arg); + return targetPaths.resolve(arg); }); if (role === 'frontend') { return buildFrontend({ - targetDir: paths.targetDir, + targetDir: targetPaths.dir, configPaths, writeStats: Boolean(opts.stats), webpack, }); } return buildBackend({ - targetDir: paths.targetDir, + targetDir: targetPaths.dir, configPaths, skipBuildDependencies: Boolean(opts.skipBuildDependencies), minify: Boolean(opts.minify), @@ -76,7 +77,7 @@ export async function command(opts: OptionValues): Promise { if (isModuleFederationRemote) { console.log('Building package as a module federation remote'); return buildFrontend({ - targetDir: paths.targetDir, + targetDir: targetPaths.dir, configPaths: [], writeStats: Boolean(opts.stats), isModuleFederationRemote, @@ -99,7 +100,7 @@ export async function command(opts: OptionValues): Promise { } const packageJson = (await fs.readJson( - paths.resolveTarget('package.json'), + targetPaths.resolve('package.json'), )) as BackstagePackageJson; return buildPackage({ diff --git a/packages/cli/src/modules/build/commands/package/start/command.ts b/packages/cli/src/modules/build/commands/package/start/command.ts index 3e3dbb378a..18f06ab0d2 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -18,13 +18,13 @@ import { OptionValues } from 'commander'; import { startPackage } from './startPackage'; import { resolveLinkedWorkspace } from './resolveLinkedWorkspace'; import { findRoleFromCommand } from '../../../lib/role'; -import { paths } from '../../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export async function command(opts: OptionValues): Promise { await startPackage({ role: await findRoleFromCommand(opts), entrypoint: opts.entrypoint, - targetDir: paths.targetDir, + targetDir: targetPaths.dir, configPaths: opts.config as string[], checksEnabled: Boolean(opts.check), linkedWorkspace: await resolveLinkedWorkspace(opts.link), diff --git a/packages/cli/src/modules/build/commands/package/start/startBackend.ts b/packages/cli/src/modules/build/commands/package/start/startBackend.ts index 525a4b0ba6..a36a93b8ff 100644 --- a/packages/cli/src/modules/build/commands/package/start/startBackend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startBackend.ts @@ -16,7 +16,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { runBackend } from '../../../lib/runner'; interface StartBackendOptions { @@ -43,7 +44,7 @@ export async function startBackend(options: StartBackendOptions) { export async function startBackendPlugin(options: StartBackendOptions) { const hasDevIndexEntry = await fs.pathExists( - resolvePath(options.targetDir ?? paths.targetDir, 'dev/index.ts'), + resolvePath(options.targetDir ?? targetPaths.dir, 'dev/index.ts'), ); if (!hasDevIndexEntry) { console.warn( diff --git a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts index 027dbf68e3..c81fd2fd66 100644 --- a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts @@ -20,7 +20,8 @@ import { getModuleFederationRemoteOptions, serveBundle, } from '../../../../build/lib/bundler'; -import { paths } from '../../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { BackstagePackageJson } from '@backstage/cli-node'; import { hasReactDomClient } from '../../../../build/lib/bundler/hasReactDomClient'; @@ -38,7 +39,7 @@ interface StartAppOptions { export async function startFrontend(options: StartAppOptions) { const packageJson = (await readJson( - resolvePath(options.targetDir ?? paths.targetDir, 'package.json'), + resolvePath(options.targetDir ?? targetPaths.dir, 'package.json'), )) as BackstagePackageJson; if (!hasReactDomClient()) { @@ -58,7 +59,7 @@ export async function startFrontend(options: StartAppOptions) { moduleFederationRemote: options.isModuleFederationRemote ? await getModuleFederationRemoteOptions( packageJson, - resolvePath(paths.targetDir), + resolvePath(targetPaths.dir), ) : undefined, }); diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index e64fe9eff0..dd65e926b2 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -18,13 +18,14 @@ import chalk from 'chalk'; import { Command, OptionValues } from 'commander'; import { relative as relativePath } from 'node:path'; import { buildPackages, getOutputsForRole } from '../../lib/builder'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { BackstagePackage, PackageGraph, PackageRoles, + runConcurrentTasks, } from '@backstage/cli-node'; -import { runParallelWorkers } from '../../../../lib/parallel'; import { buildFrontend } from '../../lib/buildFrontend'; import { buildBackend } from '../../lib/buildBackend'; import { createScriptOptionsParser } from '../../../../lib/optionsParser'; @@ -89,7 +90,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { targetDir: pkg.dir, packageJson: pkg.packageJson, outputs, - logPrefix: `${chalk.cyan(relativePath(paths.targetRoot, pkg.dir))}: `, + logPrefix: `${chalk.cyan(relativePath(targetPaths.rootDir, pkg.dir))}: `, workspacePackages: packages, minify: opts.minify ?? buildOptions.minify, }; @@ -100,9 +101,9 @@ export async function command(opts: OptionValues, cmd: Command): Promise { if (opts.all) { console.log('Building apps'); - await runParallelWorkers({ + await runConcurrentTasks({ items: apps, - parallelismFactor: 1 / 2, + concurrencyFactor: 1 / 2, worker: async pkg => { const buildOptions = parseBuildScript(pkg.packageJson.scripts?.build); if (!buildOptions) { @@ -121,9 +122,9 @@ export async function command(opts: OptionValues, cmd: Command): Promise { }); console.log('Building backends'); - await runParallelWorkers({ + await runConcurrentTasks({ items: backends, - parallelismFactor: 1 / 2, + concurrencyFactor: 1 / 2, worker: async pkg => { const buildOptions = parseBuildScript(pkg.packageJson.scripts?.build); if (!buildOptions) { diff --git a/packages/cli/src/modules/build/commands/repo/start.test.ts b/packages/cli/src/modules/build/commands/repo/start.test.ts index 0efe01df43..328c8fd365 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -16,8 +16,9 @@ import { PackageGraph } from '@backstage/cli-node'; import { findTargetPackages } from './start'; -import { posix } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; + +overrideTargetPaths('/root'); const mocks = { app: { @@ -97,11 +98,6 @@ const mocks = { describe('findTargetPackages', () => { beforeEach(() => { jest.clearAllMocks(); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...parts: string[]) => { - return posix.resolve('/root', ...parts); - }); }); it('should select default packages', async () => { diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index bc1ab543c1..f7faa46eb1 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -20,7 +20,8 @@ import { PackageRole, } from '@backstage/cli-node'; import { relative as relativePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace'; import { startPackage } from '../package/start/startPackage'; import { parseArgs } from 'node:util'; @@ -95,7 +96,7 @@ export async function findTargetPackages( pkg => nameOrPath === pkg.packageJson.name, ); if (!matchingPackage) { - const absPath = paths.resolveTargetRoot(nameOrPath); + const absPath = targetPaths.resolveRoot(nameOrPath); matchingPackage = packages.find( pkg => relativePath(pkg.dir, absPath) === '', ); @@ -117,7 +118,7 @@ export async function findTargetPackages( ); if (matchingPackages.length > 1) { // Final fallback is to check for the package path within the monorepo, packages/app or packages/backend - const expectedPath = paths.resolveTargetRoot( + const expectedPath = targetPaths.resolveRoot( role === 'frontend' ? 'packages/app' : 'packages/backend', ); const matchByPath = matchingPackages.find( diff --git a/packages/cli/src/modules/build/lib/buildBackend.ts b/packages/cli/src/modules/build/lib/buildBackend.ts index f377d068bd..bf2ebf16ba 100644 --- a/packages/cli/src/modules/build/lib/buildBackend.ts +++ b/packages/cli/src/modules/build/lib/buildBackend.ts @@ -19,7 +19,6 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import * as tar from 'tar'; import { createDistWorkspace } from './packager'; -import { getEnvironmentParallelism } from '../../../lib/parallel'; import { buildPackage, Output } from './builder'; import { PackageGraph } from '@backstage/cli-node'; @@ -53,7 +52,6 @@ export async function buildBackend(options: BuildBackendOptions) { configPaths, buildDependencies: !skipBuildDependencies, buildExcludes: [pkg.name], - parallelism: getEnvironmentParallelism(), skeleton: SKELETON_FILE, minify, }); diff --git a/packages/cli/src/modules/build/lib/buildFrontend.ts b/packages/cli/src/modules/build/lib/buildFrontend.ts index 7b0955a519..6a5785a5b9 100644 --- a/packages/cli/src/modules/build/lib/buildFrontend.ts +++ b/packages/cli/src/modules/build/lib/buildFrontend.ts @@ -17,9 +17,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { buildBundle, getModuleFederationRemoteOptions } from './bundler'; -import { getEnvironmentParallelism } from '../../../lib/parallel'; -import { loadCliConfig } from '../../config/lib/config'; import { BackstagePackageJson } from '@backstage/cli-node'; +import { loadCliConfig } from '../../config/lib/config'; interface BuildAppOptions { targetDir: string; @@ -37,7 +36,6 @@ export async function buildFrontend(options: BuildAppOptions) { await buildBundle({ targetDir, entry: 'src/index', - parallelism: getEnvironmentParallelism(), statsJsonEnabled: writeStats, moduleFederationRemote: options.isModuleFederationRemote ? await getModuleFederationRemoteOptions( diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 55ae09bf9c..4123d2ccf3 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -39,7 +39,8 @@ import { import { forwardFileImports, cssEntryPoints } from './plugins'; import { BuildOptions, Output } from './types'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../entryPoints'; @@ -116,7 +117,7 @@ export async function makeRollupConfigs( options: BuildOptions, ): Promise { const configs = new Array(); - const targetDir = options.targetDir ?? paths.targetDir; + const targetDir = options.targetDir ?? targetPaths.dir; let targetPkg = options.packageJson; if (!targetPkg) { @@ -284,9 +285,9 @@ export async function makeRollupConfigs( const input = Object.fromEntries( scriptEntryPoints.map(e => [ e.name, - paths.resolveTargetRoot( + targetPaths.resolveRoot( 'dist-types', - relativePath(paths.targetRoot, targetDir), + relativePath(targetPaths.rootDir, targetDir), e.path.replace(/\.(?:ts|tsx)$/, '.d.ts'), ), ]), diff --git a/packages/cli/src/modules/build/lib/builder/packager.ts b/packages/cli/src/modules/build/lib/builder/packager.ts index 12017b694c..cee6d0a11c 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -18,11 +18,11 @@ import fs from 'fs-extra'; import { rollup, RollupOptions } from 'rollup'; import chalk from 'chalk'; import { relative as relativePath, resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; -import { PackageRoles } from '@backstage/cli-node'; -import { runParallelWorkers } from '../../../../lib/parallel'; +import { PackageRoles, runConcurrentTasks } from '@backstage/cli-node'; export function formatErrorMessage(error: any) { let msg = ''; @@ -34,7 +34,7 @@ export function formatErrorMessage(error: any) { msg += `\n\n`; for (const { text, location } of error.errors) { const { line, column } = location; - const path = relativePath(paths.targetDir, error.id); + const path = relativePath(targetPaths.dir, error.id); const loc = chalk.cyan(`${path}:${line}:${column}`); if (text === 'Unexpected "<"' && error.id.endsWith('.js')) { @@ -53,11 +53,11 @@ export function formatErrorMessage(error: any) { } else { // Generic rollup errors, log what's available if (error.loc) { - const file = `${paths.resolveTarget((error.loc.file || error.id)!)}`; + const file = `${targetPaths.resolve((error.loc.file || error.id)!)}`; const pos = `${error.loc.line}:${error.loc.column}`; msg += `${file} [${pos}]\n`; } else if (error.id) { - msg += `${paths.resolveTarget(error.id)}\n`; + msg += `${targetPaths.resolve(error.id)}\n`; } msg += `${error}\n`; @@ -90,7 +90,7 @@ async function rollupBuild(config: RollupOptions) { export const buildPackage = async (options: BuildOptions) => { try { const { resolutions } = await fs.readJson( - paths.resolveTargetRoot('package.json'), + targetPaths.resolveRoot('package.json'), ); if (resolutions?.esbuild) { console.warn( @@ -107,7 +107,7 @@ export const buildPackage = async (options: BuildOptions) => { const rollupConfigs = await makeRollupConfigs(options); - const targetDir = options.targetDir ?? paths.targetDir; + const targetDir = options.targetDir ?? targetPaths.dir; await fs.remove(resolvePath(targetDir, 'dist')); const buildTasks = rollupConfigs.map(rollupBuild); @@ -127,7 +127,7 @@ export const buildPackages = async (options: BuildOptions[]) => { const buildTasks = rollupConfigs.flat().map(opts => () => rollupBuild(opts)); - await runParallelWorkers({ + await runConcurrentTasks({ items: buildTasks, worker: async task => task(), }); diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index a4e2b16ab9..1fe81cbec8 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -25,11 +25,12 @@ import { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack'; -import { paths as cliPaths } from '../../../../lib/paths'; + import fs from 'fs-extra'; import { optimization as optimizationConfig } from './optimization'; import pickBy from 'lodash/pickBy'; -import { runOutput } from '@backstage/cli-common'; +import { runOutput, targetPaths } from '@backstage/cli-common'; + import { transforms } from './transforms'; import { version } from '../../../../lib/version'; import yn from 'yn'; @@ -96,7 +97,7 @@ async function readBuildInfo() { } const { version: packageVersion } = await fs.readJson( - cliPaths.resolveTarget('package.json'), + targetPaths.resolve('package.json'), ); return { diff --git a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts index ad331bdf8b..9dfc3fef5f 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export function hasReactDomClient() { try { require.resolve('react-dom/client', { - paths: [paths.targetDir], + paths: [targetPaths.dir], }); return true; } catch { diff --git a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts index 39f52067ab..f724e444b4 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -17,7 +17,7 @@ import { relative as relativePath } from 'node:path'; import { getPackages } from '@manypkg/get-packages'; import { rspack } from '@rspack/core'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; /** * This returns of collection of plugins that links a separate workspace into @@ -52,7 +52,7 @@ export async function createWorkspaceLinkingPlugins( /^react(?:-router)?(?:-dom)?$/, resource => { if (!relativePath(linkedRoot.dir, resource.context).startsWith('..')) { - resource.context = paths.targetDir; + resource.context = targetPaths.dir; } }, ), diff --git a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts index 5e19c28555..307cb5cebc 100644 --- a/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts +++ b/packages/cli/src/modules/build/lib/bundler/moduleFederation.ts @@ -28,7 +28,7 @@ import { HostSharedDependencies, RuntimeSharedDependenciesGlobal, } from '@backstage/module-federation-common'; -import { dirname, join as joinPath, resolve as resolvePath } from 'path'; +import { dirname, join as joinPath, resolve as resolvePath } from 'node:path'; import fs from 'fs-extra'; import chokidar from 'chokidar'; import PQueue from 'p-queue'; diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index 47346f803b..5b4837a133 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -20,7 +20,7 @@ import chokidar from 'chokidar'; import fs from 'fs-extra'; import PQueue from 'p-queue'; import { dirname, join as joinPath, resolve as resolvePath } from 'node:path'; -import { paths as cliPaths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; const DETECTED_MODULES_MODULE_NAME = '__backstage-autodetected-plugins__'; @@ -146,7 +146,7 @@ export async function createDetectedModulesEntryPoint(options: { // Previous versions of the CLI would write the detected modules file to the // root `node_modules`, this makes sure that doesn't exist to minimize risk of conflicts const legacyDetectedModulesPath = joinPath( - cliPaths.targetRoot, + targetPaths.rootDir, 'node_modules', `${DETECTED_MODULES_MODULE_NAME}.js`, ); diff --git a/packages/cli/src/modules/build/lib/bundler/paths.ts b/packages/cli/src/modules/build/lib/bundler/paths.ts index 3106da5f7d..5a7d3b14dc 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -16,19 +16,19 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths, findOwnPaths } from '@backstage/cli-common'; export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' entry: string; - // Target directory, defaulting to paths.targetDir + // Target directory, defaulting to targetPaths.dir targetDir?: string; // Relative dist directory, defaulting to 'dist' dist?: string; }; export function resolveBundlingPaths(options: BundlingPathsOptions) { - const { entry, targetDir = paths.targetDir } = options; + const { entry, targetDir = targetPaths.dir } = options; const resolveTargetModule = (pathString: string) => { for (const ext of ['mjs', 'js', 'ts', 'tsx', 'jsx']) { @@ -49,7 +49,10 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { } else { targetHtml = resolvePath(targetDir, `${entry}.html`); if (!fs.pathExistsSync(targetHtml)) { - targetHtml = paths.resolveOwn('templates/serve_index.html'); + /* eslint-disable-next-line no-restricted-syntax */ + targetHtml = findOwnPaths(__dirname).resolve( + 'templates/serve_index.html', + ); } } @@ -67,10 +70,10 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetSrc: resolvePath(targetDir, 'src'), targetDev: resolvePath(targetDir, 'dev'), targetEntry: resolveTargetModule(entry), - targetTsConfig: paths.resolveTargetRoot('tsconfig.json'), + targetTsConfig: targetPaths.resolveRoot('tsconfig.json'), targetPackageJson: resolvePath(targetDir, 'package.json'), - rootNodeModules: paths.resolveTargetRoot('node_modules'), - root: paths.targetRoot, + rootNodeModules: targetPaths.resolveRoot('node_modules'), + root: targetPaths.rootDir, }; } diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index b2d480f061..57d6bed052 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -22,7 +22,8 @@ import openBrowser from 'react-dev-utils/openBrowser'; import { rspack } from '@rspack/core'; import { RspackDevServer } from '@rspack/dev-server'; -import { paths as libPaths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { loadCliConfig } from '../../../config/lib/config'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; @@ -53,7 +54,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be checkReactVersion(); const { name } = await fs.readJson( - resolvePath(options.targetDir ?? libPaths.targetDir, 'package.json'), + resolvePath(options.targetDir ?? targetPaths.dir, 'package.json'), ); let devServer: RspackDevServer | undefined = undefined; @@ -271,7 +272,7 @@ function checkReactVersion() { try { // Make sure we're looking at the root of the target repo const reactPkgPath = require.resolve('react/package.json', { - paths: [libPaths.targetRoot], + paths: [targetPaths.rootDir], }); const reactPkg = require(reactPkgPath); if (reactPkg.version.startsWith('16.')) { diff --git a/packages/cli/src/modules/build/lib/bundler/types.ts b/packages/cli/src/modules/build/lib/bundler/types.ts index a9a4b0f51f..d8960bc03e 100644 --- a/packages/cli/src/modules/build/lib/bundler/types.ts +++ b/packages/cli/src/modules/build/lib/bundler/types.ts @@ -36,7 +36,6 @@ export type BundlingOptions = { isDev: boolean; frontendConfig: Config; getFrontendAppConfigs(): AppConfig[]; - parallelism?: number; additionalEntryPoints?: string[]; // Path to append to the detected public path, e.g. '/public' publicSubPath?: string; @@ -63,7 +62,6 @@ export type BuildOptions = BundlingPathsOptions & { // Target directory, defaulting to paths.targetDir targetDir?: string; statsJsonEnabled: boolean; - parallelism?: number; schema?: ConfigSchema; frontendConfig: Config; frontendAppConfigs: AppConfig[]; @@ -75,7 +73,6 @@ export type BuildOptions = BundlingPathsOptions & { export type BackendBundlingOptions = { checksEnabled: boolean; isDev: boolean; - parallelism?: number; inspectEnabled: boolean; inspectBrkEnabled: boolean; require?: string; diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 0f096a3127..50fb0f4e31 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -24,8 +24,9 @@ import { import { tmpdir } from 'node:os'; import * as tar from 'tar'; import partition from 'lodash/partition'; -import { paths } from '../../../../lib/paths'; -import { run } from '@backstage/cli-common'; + +import { run, targetPaths } from '@backstage/cli-common'; + import { dependencies as cliDependencies, devDependencies as cliDevDependencies, @@ -41,8 +42,8 @@ import { PackageRoles, PackageGraph, PackageGraphNode, + runConcurrentTasks, } from '@backstage/cli-node'; -import { runParallelWorkers } from '../../../../lib/parallel'; import { createTypeDistProject } from '../../../../lib/typeDistProject'; // These packages aren't safe to pack in parallel since the CLI depends on them @@ -86,11 +87,6 @@ type Options = { */ buildExcludes?: string[]; - /** - * Controls amount of parallelism in some build steps. - */ - parallelism?: number; - /** * If set, creates a skeleton tarball that contains all package.json files * with the same structure as the workspace dir. @@ -215,7 +211,9 @@ export async function createDistWorkspace( targetDir: pkg.dir, packageJson: pkg.packageJson, outputs: outputs, - logPrefix: `${chalk.cyan(relativePath(paths.targetRoot, pkg.dir))}: `, + logPrefix: `${chalk.cyan( + relativePath(targetPaths.rootDir, pkg.dir), + )}: `, minify: options.minify, workspacePackages: packages, }); @@ -225,7 +223,7 @@ export async function createDistWorkspace( await buildPackages(standardBuilds); if (customBuild.length > 0) { - await runParallelWorkers({ + await runConcurrentTasks({ items: customBuild, worker: async ({ name, dir, args }) => { await run(['yarn', 'run', 'build', ...(args || [])], { @@ -250,13 +248,13 @@ export async function createDistWorkspace( for (const file of files) { const src = typeof file === 'string' ? file : file.src; const dest = typeof file === 'string' ? file : file.dest; - await fs.copy(paths.resolveTargetRoot(src), resolvePath(targetDir, dest)); + await fs.copy(targetPaths.resolveRoot(src), resolvePath(targetDir, dest)); } if (options.skeleton) { const skeletonFiles = targets .map(target => { - const dir = relativePath(paths.targetRoot, target.dir); + const dir = relativePath(targetPaths.rootDir, target.dir); return joinPath(dir, 'package.json'); }) .sort(); @@ -305,7 +303,7 @@ async function moveToDistWorkspace( fastPackPackages.map(async target => { console.log(`Moving ${target.name} into dist workspace`); - const outputDir = relativePath(paths.targetRoot, target.dir); + const outputDir = relativePath(targetPaths.rootDir, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await productionPack({ packageDir: target.dir, @@ -325,7 +323,7 @@ async function moveToDistWorkspace( cwd: target.dir, }).waitForExit(); - const outputDir = relativePath(paths.targetRoot, target.dir); + const outputDir = relativePath(targetPaths.rootDir, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await fs.ensureDir(absoluteOutputPath); @@ -368,7 +366,7 @@ async function moveToDistWorkspace( } // Repacking in parallel is much faster and safe for all packages outside of the Backstage repo - await runParallelWorkers({ + await runConcurrentTasks({ items: safePackages.map((target, index) => ({ target, index })), worker: async ({ target, index }) => { await pack(target, `temp-package-${index}.tgz`); diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index 89fa533457..dbed4310fa 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -15,18 +15,12 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { Command } from 'commander'; import { findRoleFromCommand } from './role'; const mockDir = createMockDirectory(); - -jest.mock('../../../lib/paths', () => ({ - paths: { - resolveTarget(filename: string) { - return mockDir.resolve(filename); - }, - }, -})); +overrideTargetPaths(mockDir.path); describe('findRoleFromCommand', () => { function mkCommand(args?: string) { diff --git a/packages/cli/src/modules/build/lib/role.ts b/packages/cli/src/modules/build/lib/role.ts index 7af4ccb955..2f3960433b 100644 --- a/packages/cli/src/modules/build/lib/role.ts +++ b/packages/cli/src/modules/build/lib/role.ts @@ -16,7 +16,8 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { PackageRoles, PackageRole } from '@backstage/cli-node'; export async function findRoleFromCommand( @@ -26,7 +27,7 @@ export async function findRoleFromCommand( return PackageRoles.getRoleInfo(opts.role)?.role; } - const pkg = await fs.readJson(paths.resolveTarget('package.json')); + const pkg = await fs.readJson(targetPaths.resolve('package.json')); const info = PackageRoles.getRoleFromPackage(pkg); if (!info) { throw new Error(`Target package must have 'backstage.role' set`); diff --git a/packages/cli/src/modules/build/lib/runner/runBackend.ts b/packages/cli/src/modules/build/lib/runner/runBackend.ts index d8fd447326..22fd50b3f4 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -21,7 +21,8 @@ import { IpcServer, ServerDataStore } from '../ipc'; import debounce from 'lodash/debounce'; import { fileURLToPath } from 'node:url'; import { isAbsolute as isAbsolutePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import spawn from 'cross-spawn'; const loaderArgs = [ @@ -135,7 +136,7 @@ export async function runBackend(options: RunBackendOptions) { ...process.env, BACKSTAGE_CLI_LINKED_WORKSPACE: options.linkedWorkspace, BACKSTAGE_CLI_CHANNEL: '1', - ESBK_TSCONFIG_PATH: paths.resolveTargetRoot('tsconfig.json'), + ESBK_TSCONFIG_PATH: targetPaths.resolveRoot('tsconfig.json'), }, serialization: 'advanced', }, diff --git a/packages/cli/src/modules/config/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts index 2b313f60bd..1d920eb31e 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -16,7 +16,8 @@ import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { paths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; @@ -34,7 +35,7 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const targetDir = options.targetDir ?? paths.targetDir; + const targetDir = options.targetDir ?? targetPaths.dir; // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(targetDir); @@ -63,7 +64,7 @@ export async function loadCliConfig(options: Options) { const schema = await loadConfigSchema({ dependencies: localPackageNames, // Include the package.json in the project root if it exists - packagePaths: [paths.resolveTargetRoot('package.json')], + packagePaths: [targetPaths.resolveRoot('package.json')], noUndeclaredProperties: options.strict, }); @@ -73,7 +74,7 @@ export async function loadCliConfig(options: Options) { ? async name => process.env[name] || 'x' : undefined, watch: Boolean(options.watch), - rootDir: paths.targetRoot, + rootDir: targetPaths.rootDir, argv: options.args.flatMap(t => ['--config', resolvePath(targetDir, t)]), }); diff --git a/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts b/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts index 6c0e422080..57aca5674f 100644 --- a/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts +++ b/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts @@ -18,7 +18,8 @@ import fs from 'fs-extra'; import chalk from 'chalk'; import { stringify as stringifyYaml } from 'yaml'; import inquirer, { Question, Answers } from 'inquirer'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { GithubCreateAppServer } from './GithubCreateAppServer'; import openBrowser from 'react-dev-utils/openBrowser'; @@ -62,7 +63,7 @@ export default async (org: string) => { const fileName = `github-app-${slug}-credentials.yaml`; const content = `# Name: ${name}\n${stringifyYaml(config)}`; - await fs.writeFile(paths.resolveTargetRoot(fileName), content); + await fs.writeFile(targetPaths.resolveRoot(fileName), content); console.log(`GitHub App configuration written to ${chalk.cyan(fileName)}`); console.log( chalk.yellow( diff --git a/packages/cli/src/modules/info/commands/info.ts b/packages/cli/src/modules/info/commands/info.ts index 923a02ef4c..c50a9da373 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -16,8 +16,7 @@ import { version as cliVersion } from '../../../../package.json'; import os from 'node:os'; -import { runOutput } from '@backstage/cli-common'; -import { paths } from '../../../lib/paths'; +import { runOutput, targetPaths, findOwnPaths } from '@backstage/cli-common'; import { Lockfile } from '../../../lib/versioning'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; import { minimatch } from 'minimatch'; @@ -56,9 +55,10 @@ function hasBackstageField(packageName: string, targetPath: string): boolean { export default async (options: InfoOptions) => { await new Promise(async () => { const yarnVersion = await runOutput(['yarn', '--version']); - const isLocal = fs.existsSync(paths.resolveOwn('./src')); + /* eslint-disable-next-line no-restricted-syntax */ + const isLocal = fs.existsSync(findOwnPaths(__dirname).resolve('./src')); - const backstageFile = paths.resolveTargetRoot('backstage.json'); + const backstageFile = targetPaths.resolveRoot('backstage.json'); let backstageVersion = 'N/A'; if (fs.existsSync(backstageFile)) { try { @@ -83,9 +83,9 @@ export default async (options: InfoOptions) => { backstage: backstageVersion, }; - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); - const targetPath = paths.targetRoot; + const targetPath = targetPaths.rootDir; // Get workspace package names and their versions const workspacePackages = new Map(); diff --git a/packages/cli/src/modules/lint/commands/package/lint.ts b/packages/cli/src/modules/lint/commands/package/lint.ts index a1e45c0113..0a453ac71a 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -16,12 +16,13 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { const eslint = new ESLint({ - cwd: paths.targetDir, + cwd: targetPaths.dir, fix: opts.fix, extensions: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'], }); @@ -47,14 +48,14 @@ export default async (directories: string[], opts: OptionValues) => { // This formatter uses the cwd to format file paths, so let's have that happen from the root instead if (opts.format === 'eslint-formatter-friendly') { - process.chdir(paths.targetRoot); + process.chdir(targetPaths.rootDir); } const resultText = await formatter.format(results); if (resultText) { if (opts.outputFile) { - await fs.writeFile(paths.resolveTarget(opts.outputFile), resultText); + await fs.writeFile(targetPaths.resolve(opts.outputFile), resultText); } else { console.log(resultText); } diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 458ccf1a63..dafcff45c6 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -23,9 +23,10 @@ import { PackageGraph, BackstagePackageJson, Lockfile, + runWorkerQueueThreads, } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; -import { runWorkerQueueThreads } from '../../../../lib/parallel'; +import { targetPaths } from '@backstage/cli-common'; + import { createScriptOptionsParser } from '../../../../lib/optionsParser'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; @@ -44,7 +45,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { const cacheContext = opts.successCache ? { entries: await cache.read(), - lockfile: await Lockfile.load(paths.resolveTargetRoot('yarn.lock')), + lockfile: await Lockfile.load(targetPaths.resolveRoot('yarn.lock')), } : undefined; @@ -62,7 +63,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { // This formatter uses the cwd to format file paths, so let's have that happen from the root instead if (opts.format === 'eslint-formatter-friendly') { - process.chdir(paths.targetRoot); + process.chdir(targetPaths.rootDir); } // Make sure lint output is colored unless the user explicitly disabled it @@ -77,7 +78,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { const lintOptions = parseLintScript(pkg.packageJson.scripts?.lint); const base = { fullDir: pkg.dir, - relativeDir: relativePath(paths.targetRoot, pkg.dir), + relativeDir: relativePath(targetPaths.rootDir, pkg.dir), lintOptions, parentHash: undefined, }; @@ -105,15 +106,15 @@ export async function command(opts: OptionValues, cmd: Command): Promise { }), ); - const resultsList = await runWorkerQueueThreads({ + const { results: resultsList } = await runWorkerQueueThreads({ items: items.filter(item => item.lintOptions), // Filter out packages without lint script - workerData: { + context: { fix: Boolean(opts.fix), format: opts.format as string | undefined, shouldCache: Boolean(cacheContext), maxWarnings: opts.maxWarnings ?? -1, successCache: cacheContext?.entries, - rootDir: paths.targetRoot, + rootDir: targetPaths.rootDir, }, workerFactory: async ({ fix, @@ -263,7 +264,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { } if (opts.outputFile && errorOutput) { - await fs.writeFile(paths.resolveTargetRoot(opts.outputFile), errorOutput); + await fs.writeFile(targetPaths.resolveRoot(opts.outputFile), errorOutput); } if (cacheContext) { diff --git a/packages/cli/src/modules/maintenance/commands/package/clean.ts b/packages/cli/src/modules/maintenance/commands/package/clean.ts index 5e2d0d65b3..70d7ea3771 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -15,10 +15,10 @@ */ import fs from 'fs-extra'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export default async function clean() { - await fs.remove(paths.resolveTarget('dist')); - await fs.remove(paths.resolveTarget('dist-types')); - await fs.remove(paths.resolveTarget('coverage')); + await fs.remove(targetPaths.resolve('dist')); + await fs.remove(targetPaths.resolve('dist-types')); + await fs.remove(targetPaths.resolve('coverage')); } diff --git a/packages/cli/src/modules/maintenance/commands/package/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts index cdd50517ae..e5e176d17e 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -18,23 +18,24 @@ import { productionPack, revertProductionPack, } from '../../../../modules/build/lib/packager/productionPack'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import fs from 'fs-extra'; import { publishPreflightCheck } from '../../lib/publishing'; import { createTypeDistProject } from '../../../../lib/typeDistProject'; export const pre = async () => { publishPreflightCheck({ - dir: paths.targetDir, - packageJson: await fs.readJson(paths.resolveTarget('package.json')), + dir: targetPaths.dir, + packageJson: await fs.readJson(targetPaths.resolve('package.json')), }); await productionPack({ - packageDir: paths.targetDir, + packageDir: targetPaths.dir, featureDetectionProject: await createTypeDistProject(), }); }; export const post = async () => { - await revertProductionPack(paths.targetDir); + await revertProductionPack(targetPaths.dir); }; diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index 59e5367837..28b123fa9e 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -17,15 +17,15 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; -import { run } from '@backstage/cli-common'; + +import { run, targetPaths } from '@backstage/cli-common'; export async function command(): Promise { const packages = await PackageGraph.listTargetPackages(); - await fs.remove(paths.resolveTargetRoot('dist')); - await fs.remove(paths.resolveTargetRoot('dist-types')); - await fs.remove(paths.resolveTargetRoot('coverage')); + await fs.remove(targetPaths.resolveRoot('dist')); + await fs.remove(targetPaths.resolveRoot('dist-types')); + await fs.remove(targetPaths.resolveRoot('coverage')); await Promise.all( Array.from(Array(10), async () => { diff --git a/packages/cli/src/modules/maintenance/commands/repo/fix.ts b/packages/cli/src/modules/maintenance/commands/repo/fix.ts index a5c6b519ed..073cb69ea1 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -29,7 +29,8 @@ import { relative as relativePath, extname, } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { publishPreflightCheck } from '../../lib/publishing'; const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx', '.json']; @@ -49,7 +50,7 @@ export async function readFixablePackages(): Promise { export function printPackageFixHint(packages: FixablePackage[]) { const changed = packages.filter(pkg => pkg.changed); if (changed.length > 0) { - const rootPkg = require(paths.resolveTargetRoot('package.json')); + const rootPkg = require(targetPaths.resolveRoot('package.json')); const fixCmd = rootPkg.scripts?.fix === 'backstage-cli repo fix' ? 'fix' @@ -216,7 +217,7 @@ export function fixSideEffects(pkg: FixablePackage) { } export function createRepositoryFieldFixer() { - const rootPkg = require(paths.resolveTargetRoot('package.json')); + const rootPkg = require(targetPaths.resolveRoot('package.json')); const rootRepoField = rootPkg.repository; if (!rootRepoField) { return () => {}; @@ -229,7 +230,7 @@ export function createRepositoryFieldFixer() { return (pkg: FixablePackage) => { const expectedPath = posix.join( rootDir, - relativePath(paths.targetRoot, pkg.dir), + relativePath(targetPaths.rootDir, pkg.dir), ); const repoField = pkg.packageJson.repository; @@ -318,7 +319,7 @@ export function fixPluginId(pkg: FixablePackage) { role === 'backend-plugin-module') ) { const path = relativePath( - paths.targetRoot, + targetPaths.rootDir, resolvePath(pkg.dir, 'package.json'), ); const msg = `Failed to guess plugin ID for "${pkg.packageJson.name}", please set the 'backstage.pluginId' field manually in "${path}"`; @@ -414,7 +415,7 @@ export function fixPluginPackages( return; } const path = relativePath( - paths.targetRoot, + targetPaths.rootDir, resolvePath(pkg.dir, 'package.json'), ); const suggestedRole = @@ -463,7 +464,7 @@ export function fixPeerModules(pkg: FixablePackage) { } const packagePath = relativePath( - paths.targetRoot, + targetPaths.rootDir, resolvePath(pkg.dir, 'package.json'), ); diff --git a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts index b89058e9fb..f4114838a1 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -19,20 +19,20 @@ import { ESLint } from 'eslint'; import { OptionValues } from 'commander'; import { relative as relativePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); const eslint = new ESLint({ - cwd: paths.targetDir, + cwd: targetPaths.dir, overrideConfig: { plugins: ['deprecation'], rules: { 'deprecation/deprecation': 'error', }, parserOptions: { - project: [paths.resolveTargetRoot('tsconfig.json')], + project: [targetPaths.resolveRoot('tsconfig.json')], }, }, extensions: ['jsx', 'ts', 'tsx', 'mjs', 'cjs'], @@ -52,7 +52,7 @@ export async function command(opts: OptionValues) { continue; } - const path = relativePath(paths.targetRoot, result.filePath); + const path = relativePath(targetPaths.rootDir, result.filePath); deprecations.push({ path, message: message.message, diff --git a/packages/cli/src/modules/migrate/commands/packageRole.ts b/packages/cli/src/modules/migrate/commands/packageRole.ts index 58c1487149..6b422c375e 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -18,10 +18,10 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { getPackages } from '@manypkg/get-packages'; import { PackageRoles } from '@backstage/cli-node'; -import { paths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export default async () => { - const { packages } = await getPackages(paths.targetDir); + const { packages } = await getPackages(targetPaths.dir); await Promise.all( packages.map(async ({ dir, packageJson: pkg }) => { diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts index affd5a9aee..598f05acce 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -16,16 +16,14 @@ import fs from 'fs-extra'; import { Command } from 'commander'; import * as runObj from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; import { registerMswTestHooks, withLogCollector } from '@backstage/test-utils'; import { YarnInfoInspectData } from '../../../../lib/versioning/packages'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { NotFoundError } from '@backstage/errors'; -import { - createMockDirectory, - MockDirectory, -} from '@backstage/backend-test-utils'; +import { createMockDirectory } from '@backstage/backend-test-utils'; // Avoid mutating the global agents used in other tests jest.mock('global-agent', () => ({ @@ -59,19 +57,10 @@ jest.mock('ora', () => ({ }, })); -let mockDir: MockDirectory; jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - findPaths: () => ({ - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); - }, - get targetDir() { - return mockDir.path; - }, - }), run: jest.fn().mockReturnValue({ exitCode: null, waitForExit: jest.fn().mockResolvedValue(undefined), @@ -138,9 +127,10 @@ const expectLogsToMatch = ( }; describe('bump', () => { - mockDir = createMockDirectory(); + const mockDir = createMockDirectory(); beforeEach(() => { + overrideTargetPaths(mockDir.path); mockFetchPackageInfo.mockImplementation(async name => ({ name: name, 'dist-tags': { @@ -928,7 +918,11 @@ describe('bump', () => { }); describe('bumpBackstageJsonVersion', () => { - mockDir = createMockDirectory(); + const mockDir = createMockDirectory(); + + beforeEach(() => { + overrideTargetPaths(mockDir.path); + }); afterEach(() => { jest.resetAllMocks(); @@ -1062,9 +1056,15 @@ describe('createVersionFinder', () => { }); describe('environment variables', () => { + const mockDir = createMockDirectory(); + const worker = setupServer(); registerMswTestHooks(worker); + beforeEach(() => { + overrideTargetPaths(mockDir.path); + }); + beforeEach(() => { delete process.env.BACKSTAGE_MANIFEST_FILE; process.env.BACKSTAGE_VERSIONS_BASE_URL = 'https://custom.example.com'; diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index ab65f8c604..4283028216 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BACKSTAGE_JSON, bootstrapEnvProxyAgents } from '@backstage/cli-common'; +import { + BACKSTAGE_JSON, + bootstrapEnvProxyAgents, + targetPaths, +} from '@backstage/cli-common'; bootstrapEnvProxyAgents(); @@ -25,7 +29,7 @@ import semver from 'semver'; import { OptionValues } from 'commander'; import { isError, NotFoundError } from '@backstage/errors'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; + import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; import { fetchPackageInfo, @@ -33,7 +37,7 @@ import { mapDependencies, YarnInfoInspectData, } from '../../../../lib/versioning'; -import { runParallelWorkers } from '../../../../lib/parallel'; +import { runConcurrentTasks } from '@backstage/cli-node'; import { getManifestByReleaseLine, getManifestByVersion, @@ -68,7 +72,7 @@ function extendsDefaultPattern(pattern: string): boolean { } export default async (opts: OptionValues) => { - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); const hasYarnPlugin = await getHasYarnPlugin(); @@ -140,13 +144,13 @@ export default async (opts: OptionValues) => { } // First we discover all Backstage dependencies within our own repo - const dependencyMap = await mapDependencies(paths.targetDir, pattern); + const dependencyMap = await mapDependencies(targetPaths.dir, pattern); // Next check with the package registry to see which dependency ranges we need to bump const versionBumps = new Map(); - await runParallelWorkers({ - parallelismFactor: 4, + await runConcurrentTasks({ + concurrencyFactor: 4, items: dependencyMap.entries(), async worker([name, pkgs]) { let target: string; @@ -182,8 +186,8 @@ export default async (opts: OptionValues) => { console.log(); const breakingUpdates = new Map(); - await runParallelWorkers({ - parallelismFactor: 4, + await runConcurrentTasks({ + concurrencyFactor: 4, items: versionBumps.entries(), async worker([name, deps]) { const pkgPath = resolvePath(deps[0].location, 'package.json'); @@ -417,7 +421,7 @@ export function createVersionFinder(options: { } function getBackstageJsonPath() { - return paths.resolveTargetRoot(BACKSTAGE_JSON); + return targetPaths.resolveRoot(BACKSTAGE_JSON); } async function getBackstageJson() { diff --git a/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts index 533bdaa954..6748f8c1ff 100644 --- a/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts @@ -18,6 +18,7 @@ import { createMockDirectory, } from '@backstage/backend-test-utils'; import * as runObj from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import migrate from './migrate'; import { withLogCollector } from '@backstage/test-utils'; import fs from 'fs-extra'; @@ -38,9 +39,7 @@ jest.mock('@backstage/cli-common', () => { return { ...actual, findPaths: () => ({ - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); - }, + resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), get targetDir() { return mockDir.path; }, @@ -58,6 +57,7 @@ function expectLogsToMatch(receivedLogs: String[], expected: String[]): void { describe('versions:migrate', () => { mockDir = createMockDirectory(); + beforeAll(() => overrideTargetPaths(mockDir.path)); beforeEach(() => { (runObj.run as jest.Mock).mockReturnValue({ diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index 1cfddabffb..c0cddba126 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import path from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; @@ -82,7 +82,7 @@ export async function addCodeownersEntry( let filePath = codeownersFilePath; if (!filePath) { - filePath = await getCodeownersFilePath(paths.targetRoot); + filePath = await getCodeownersFilePath(targetPaths.rootDir); if (!filePath) { return false; } diff --git a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts index 9dfd60baba..511e656c91 100644 --- a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts +++ b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts @@ -25,7 +25,8 @@ import upperCase from 'lodash/upperCase'; import upperFirst from 'lodash/upperFirst'; import lowerFirst from 'lodash/lowerFirst'; import { Lockfile } from '../../../../lib/versioning'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { createPackageVersionProvider } from '../../../../lib/version'; import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; @@ -49,7 +50,7 @@ export class PortableTemplater { static async create(options: CreatePortableTemplaterOptions = {}) { let lockfile: Lockfile | undefined; try { - lockfile = await Lockfile.load(paths.resolveTargetRoot('yarn.lock')); + lockfile = await Lockfile.load(targetPaths.resolveRoot('yarn.lock')); } catch { /* ignored */ } diff --git a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts index 0fe0284386..4bbb3730df 100644 --- a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts +++ b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts @@ -16,7 +16,8 @@ import fs from 'fs-extra'; import upperFirst from 'lodash/upperFirst'; import camelCase from 'lodash/camelCase'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { Task } from '../tasks'; import { PortableTemplateInput } from '../types'; @@ -52,7 +53,7 @@ export async function installNewPackage(input: PortableTemplateInput) { } async function addDependency(input: PortableTemplateInput, path: string) { - const pkgJsonPath = paths.resolveTargetRoot(path); + const pkgJsonPath = targetPaths.resolveRoot(path); const pkgJson = await fs.readJson(pkgJsonPath).catch(error => { if (error.code === 'ENOENT') { @@ -84,7 +85,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { ); } - const appDefinitionPath = paths.resolveTargetRoot('packages/app/src/App.tsx'); + const appDefinitionPath = targetPaths.resolveRoot('packages/app/src/App.tsx'); if (!(await fs.pathExists(appDefinitionPath))) { return; } @@ -120,7 +121,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { } async function tryAddBackend(input: PortableTemplateInput) { - const backendIndexPath = paths.resolveTargetRoot( + const backendIndexPath = targetPaths.resolveRoot( 'packages/backend/src/index.ts', ); if (!(await fs.pathExists(backendIndexPath))) { diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts index a9f1ad61f7..8132246be6 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts @@ -17,7 +17,10 @@ import { relative as relativePath } from 'node:path'; import { writeTemplateContents } from './writeTemplateContents'; import { createMockDirectory } from '@backstage/backend-test-utils'; -import { paths } from '../../../../lib/paths'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; + +const mockDir = createMockDirectory(); +overrideTargetPaths(mockDir.path); const baseConfig = { version: '0.1.0', @@ -26,14 +29,14 @@ const baseConfig = { }; describe('writeTemplateContents', () => { - const mockDir = createMockDirectory(); - beforeEach(() => { mockDir.clear(); + mockDir.setContent({ + 'package.json': JSON.stringify({ + workspaces: { packages: ['packages/*', 'plugins/*'] }, + }), + }); jest.resetAllMocks(); - jest - .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...args) => mockDir.resolve(...args)); }); it('should write an empty template', async () => { @@ -53,7 +56,11 @@ describe('writeTemplateContents', () => { ); expect(relativePath(mockDir.path, targetDir)).toBe('plugins/plugin-test'); - expect(mockDir.content()).toEqual({}); + expect(mockDir.content()).toEqual({ + 'package.json': JSON.stringify({ + workspaces: { packages: ['packages/*', 'plugins/*'] }, + }), + }); }); it('should write template with various files', async () => { @@ -87,6 +94,9 @@ describe('writeTemplateContents', () => { ); expect(mockDir.content()).toEqual({ + 'package.json': JSON.stringify({ + workspaces: { packages: ['packages/*', 'plugins/*'] }, + }), out: { 'test.txt': 'test', 'plugin.txt': 'id=test', diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index 8b2f9ebf1e..619a6fc3f2 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -17,18 +17,17 @@ import fs from 'fs-extra'; import { dirname, resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; import { PortableTemplate, PortableTemplateInput } from '../types'; import { ForwardedError, InputError } from '@backstage/errors'; import { isMonoRepo as getIsMonoRepo } from '@backstage/cli-node'; import { PortableTemplater } from './PortableTemplater'; -import { isChildPath } from '@backstage/cli-common'; +import { isChildPath, targetPaths } from '@backstage/cli-common'; export async function writeTemplateContents( template: PortableTemplate, input: PortableTemplateInput, ): Promise<{ targetDir: string }> { - const targetDir = paths.resolveTargetRoot(input.packagePath); + const targetDir = targetPaths.resolveRoot(input.packagePath); if (await fs.pathExists(targetDir)) { throw new InputError(`Package '${input.packagePath}' already exists`); diff --git a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts index 38e8eaddba..7279801d62 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -16,7 +16,8 @@ import inquirer, { DistinctQuestion } from 'inquirer'; import { getCodeownersFilePath, parseOwnerIds } from '../codeowners'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { PortableTemplateConfig, PortableTemplateInput, @@ -38,7 +39,7 @@ export async function collectPortableTemplateInput( ): Promise { const { config, template, prefilledParams } = options; - const codeOwnersFilePath = await getCodeownersFilePath(paths.targetRoot); + const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.rootDir); const prompts = getPromptsForRole(template.role); diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts index f7053df552..6a683fb31c 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts @@ -20,7 +20,8 @@ import recursiveReaddir from 'recursive-readdir'; import { resolve as resolvePath, relative as relativePath } from 'node:path'; import { dirname } from 'node:path'; import { parse as parseYaml } from 'yaml'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { PortableTemplateFile, PortableTemplatePointer, @@ -46,7 +47,7 @@ export async function loadPortableTemplate( throw new Error('Remote templates are not supported yet'); } const templateContent = await fs - .readFile(paths.resolveTargetRoot(pointer.target), 'utf-8') + .readFile(targetPaths.resolveRoot(pointer.target), 'utf-8') .catch(error => { throw new ForwardedError( `Failed to load template definition from '${pointer.target}'`, diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts index dd937482a2..5040904138 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts @@ -16,7 +16,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath, dirname, isAbsolute } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; + import { defaultTemplates } from '../defaultTemplates'; import { PortableTemplateConfig, @@ -90,7 +91,7 @@ export async function loadPortableTemplateConfig( ): Promise { const { overrides = {} } = options; const pkgPath = - options.packagePath ?? paths.resolveTargetRoot('package.json'); + options.packagePath ?? targetPaths.resolveRoot('package.json'); const pkgJson = await fs.readJson(pkgPath); const parsed = pkgJsonWithNewConfigSchema.safeParse(pkgJson); diff --git a/packages/cli/src/modules/test/commands/package/test.ts b/packages/cli/src/modules/test/commands/package/test.ts index 992697d19c..c4acfb287b 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -15,8 +15,8 @@ */ import { Command, OptionValues } from 'commander'; -import { paths } from '../../../../lib/paths'; -import { runCheck } from '@backstage/cli-common'; + +import { runCheck, findOwnPaths } from '@backstage/cli-common'; function includesAnyOf(hayStack: string[], ...needles: string[]) { for (const needle of needles) { @@ -38,7 +38,8 @@ export default async (_opts: OptionValues, cmd: Command) => { // Only include our config if caller isn't passing their own config if (!includesAnyOf(args, '-c', '--config')) { - args.push('--config', paths.resolveOwn('config/jest.js')); + /* eslint-disable-next-line no-restricted-syntax */ + args.push('--config', findOwnPaths(__dirname).resolve('config/jest.js')); } if (!includesAnyOf(args, '--no-passWithNoTests', '--passWithNoTests=false')) { diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index f4d488ee0e..1f57279935 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -23,9 +23,14 @@ import { run as runJest, yargsOptions as jestYargsOptions } from 'jest-cli'; import { relative as relativePath } from 'node:path'; import { Command, OptionValues } from 'commander'; import { Lockfile, PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; -import { runCheck, runOutput } from '@backstage/cli-common'; -import { isChildPath } from '@backstage/cli-common'; + +import { + runCheck, + runOutput, + targetPaths, + findOwnPaths, + isChildPath, +} from '@backstage/cli-common'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; type JestProject = { @@ -63,7 +68,7 @@ interface TestGlobal extends Global { async function readPackageTreeHashes(graph: PackageGraph) { const pkgs = Array.from(graph.values()).map(pkg => ({ ...pkg, - path: relativePath(paths.targetRoot, pkg.dir), + path: relativePath(targetPaths.rootDir, pkg.dir), })); const output = await runOutput([ 'git', @@ -162,7 +167,8 @@ export async function command(opts: OptionValues, cmd: Command): Promise { // Only include our config if caller isn't passing their own config if (!hasFlags('-c', '--config')) { - args.push('--config', paths.resolveOwn('config/jest.js')); + /* eslint-disable-next-line no-restricted-syntax */ + args.push('--config', findOwnPaths(__dirname).resolve('config/jest.js')); } if (!hasFlags('--passWithNoTests')) { @@ -341,7 +347,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { async filterConfigs(projectConfigs, globalRootConfig) { const cacheEntries = await cache.read(); const lockfile = await Lockfile.load( - paths.resolveTargetRoot('yarn.lock'), + targetPaths.resolveRoot('yarn.lock'), ); const getPackageTreeHash = await readPackageTreeHashes(graph); diff --git a/packages/cli/src/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts new file mode 100644 index 0000000000..0329b1241a --- /dev/null +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -0,0 +1,139 @@ +/* + * Copyright 2026 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 { targetPaths } from '@backstage/cli-common'; +import fs from 'fs-extra'; +import { dirname, resolve as resolvePath } from 'node:path'; +import { + discoverFrontendPackages, + readTargetPackage, +} from '../lib/discoverPackages'; +import { + createTranslationProject, + extractTranslationRefsFromSourceFile, + TranslationRefInfo, +} from '../lib/extractTranslations'; +import { + DEFAULT_LANGUAGE, + formatMessagePath, + validatePattern, +} from '../lib/messageFilePath'; + +interface ExportOptions { + output: string; + pattern: string; +} + +export default async (options: ExportOptions) => { + validatePattern(options.pattern); + + const targetPackageJson = await readTargetPackage( + targetPaths.dir, + targetPaths.rootDir, + ); + + const outputDir = resolvePath(targetPaths.dir, options.output); + const manifestPath = resolvePath(outputDir, 'manifest.json'); + + const tsconfigPath = targetPaths.resolveRoot('tsconfig.json'); + if (!(await fs.pathExists(tsconfigPath))) { + throw new Error( + `No tsconfig.json found at ${tsconfigPath}. ` + + 'The translations export command requires a tsconfig.json in the repo root.', + ); + } + + console.log( + `Discovering frontend dependencies of ${targetPackageJson.name}...`, + ); + const packages = await discoverFrontendPackages( + targetPackageJson, + targetPaths.dir, + ); + console.log(`Found ${packages.length} frontend packages to scan`); + + console.log('Creating TypeScript project...'); + const project = createTranslationProject(tsconfigPath); + + const allRefs: TranslationRefInfo[] = []; + + for (const pkg of packages) { + for (const [exportPath, filePath] of pkg.entryPoints) { + try { + const sourceFile = project.addSourceFileAtPath(filePath); + const refs = extractTranslationRefsFromSourceFile( + sourceFile, + pkg.name, + exportPath, + ); + allRefs.push(...refs); + } catch (error) { + console.warn( + ` Warning: failed to process ${pkg.name} (${exportPath}): ${error}`, + ); + } + } + } + + if (allRefs.length === 0) { + console.log('No translation refs found.'); + return; + } + + console.log(`Found ${allRefs.length} translation ref(s):`); + for (const ref of allRefs) { + const messageCount = Object.keys(ref.messages).length; + console.log(` ${ref.id} (${ref.packageName}, ${messageCount} messages)`); + } + + // Write message files using the configured pattern + for (const ref of allRefs) { + const relPath = formatMessagePath( + options.pattern, + ref.id, + DEFAULT_LANGUAGE, + ); + const filePath = resolvePath(outputDir, relPath); + await fs.ensureDir(dirname(filePath)); + await fs.writeJson(filePath, ref.messages, { spaces: 2 }); + } + + // Write manifest + const manifest: Record = {}; + for (const ref of allRefs) { + manifest[ref.id] = { + package: ref.packageName, + exportPath: ref.exportPath, + exportName: ref.exportName, + }; + } + await fs.writeJson( + manifestPath, + { pattern: options.pattern, refs: manifest }, + { spaces: 2 }, + ); + + const examplePath = formatMessagePath( + options.pattern, + '', + DEFAULT_LANGUAGE, + ); + console.log( + `\nExported ${allRefs.length} translation ref(s) to ${options.output}/`, + ); + console.log(` Messages: ${options.output}/${examplePath}`); + console.log(` Manifest: ${options.output}/manifest.json`); +}; diff --git a/packages/cli/src/modules/translations/commands/import.ts b/packages/cli/src/modules/translations/commands/import.ts new file mode 100644 index 0000000000..c104275f46 --- /dev/null +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -0,0 +1,214 @@ +/* + * Copyright 2026 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 { targetPaths } from '@backstage/cli-common'; +import fs from 'fs-extra'; +import { + resolve as resolvePath, + relative as relativePath, + sep, +} from 'node:path'; +import { readTargetPackage } from '../lib/discoverPackages'; +import { + DEFAULT_LANGUAGE, + createMessagePathParser, + formatMessagePath, +} from '../lib/messageFilePath'; + +interface ImportOptions { + input: string; + output: string; +} + +interface ManifestRefEntry { + package: string; + exportPath: string; + exportName: string; +} + +interface Manifest { + pattern?: string; + refs: Record; +} + +export default async (options: ImportOptions) => { + await readTargetPackage(targetPaths.dir, targetPaths.rootDir); + + const inputDir = resolvePath(targetPaths.dir, options.input); + const manifestPath = resolvePath(inputDir, 'manifest.json'); + const outputPath = resolvePath(targetPaths.dir, options.output); + + if (!(await fs.pathExists(manifestPath))) { + throw new Error( + `No manifest.json found at ${manifestPath}. ` + + 'Run "backstage-cli translations export" first.', + ); + } + + const manifest: Manifest = await fs.readJson(manifestPath); + + if (!manifest.pattern) { + throw new Error( + 'No pattern found in manifest.json. Re-run "backstage-cli translations export" to regenerate it.', + ); + } + const pattern = manifest.pattern; + + const parsePath = createMessagePathParser(pattern); + + // Discover all JSON files under the translations directory + const allFiles = (await collectJsonFiles(inputDir)).filter( + f => f !== 'manifest.json', + ); + + // Parse each file to extract id + lang, filtering out default language files + const translationsByRef = new Map< + string, + Array<{ lang: string; relPath: string }> + >(); + let skipped = 0; + + for (const relPath of allFiles) { + const parsed = parsePath(relPath); + if (!parsed) { + skipped++; + continue; + } + + if (parsed.lang === DEFAULT_LANGUAGE) { + continue; + } + + if (!manifest.refs[parsed.id]) { + console.warn( + ` Warning: skipping ${relPath} - ref '${parsed.id}' not found in manifest`, + ); + continue; + } + + const existing = translationsByRef.get(parsed.id) ?? []; + existing.push({ lang: parsed.lang, relPath }); + translationsByRef.set(parsed.id, existing); + } + + if (skipped > 0) { + console.warn( + ` Warning: ${skipped} file(s) did not match the pattern '${pattern}'`, + ); + } + + if (translationsByRef.size === 0) { + console.log('No translated message files found.'); + const example = formatMessagePath(pattern, '', 'sv'); + console.log( + `Add translated files as ${example} in the translations directory.`, + ); + return; + } + + // Generate the wiring module + const importLines: string[] = []; + const resourceLines: string[] = []; + + importLines.push( + "import { createTranslationResource } from '@backstage/frontend-plugin-api';", + ); + + for (const [refId, entries] of [...translationsByRef.entries()].sort( + ([a], [b]) => a.localeCompare(b), + )) { + const refEntry = manifest.refs[refId]; + const importPath = + refEntry.exportPath === '.' + ? refEntry.package + : `${refEntry.package}/${refEntry.exportPath.replace(/^\.\//, '')}`; + + importLines.push(`import { ${refEntry.exportName} } from '${importPath}';`); + + const translationEntries = entries + .sort((a, b) => a.lang.localeCompare(b.lang)) + .map(({ lang, relPath }) => { + const jsonRelPath = relativePath( + resolvePath(outputPath, '..'), + resolvePath(inputDir, relPath), + ) + .split(sep) + .join('/'); + return ` ${JSON.stringify(lang)}: () => import('./${jsonRelPath}'),`; + }) + .join('\n'); + + resourceLines.push( + [ + ` createTranslationResource({`, + ` ref: ${refEntry.exportName},`, + ` translations: {`, + translationEntries, + ` },`, + ` }),`, + ].join('\n'), + ); + } + + const fileContent = [ + '// This file is auto-generated by backstage-cli translations import', + '// Do not edit manually.', + '', + ...importLines, + '', + 'export default [', + ...resourceLines, + '];', + '', + ].join('\n'); + + await fs.ensureDir(resolvePath(outputPath, '..')); + await fs.writeFile(outputPath, fileContent, 'utf8'); + + const totalFiles = [...translationsByRef.values()].reduce( + (sum, e) => sum + e.length, + 0, + ); + console.log(`Generated translation resources at ${options.output}`); + console.log( + ` ${translationsByRef.size} ref(s), ${totalFiles} translation file(s)`, + ); + console.log( + '\nImport this file in your app and pass the resources to your translation API setup.', + ); +}; + +/** + * Recursively collects all .json files under a directory, returning paths + * relative to that directory using forward slashes. + */ +async function collectJsonFiles(dir: string, prefix = ''): Promise { + const entries = await fs.readdir(dir, { withFileTypes: true }); + const results: string[] = []; + + for (const entry of entries) { + const relPath = prefix ? `${prefix}/${entry.name}` : entry.name; + if (entry.isDirectory()) { + results.push( + ...(await collectJsonFiles(resolvePath(dir, entry.name), relPath)), + ); + } else if (entry.isFile() && entry.name.endsWith('.json')) { + results.push(relPath); + } + } + + return results; +} diff --git a/packages/cli/src/modules/translations/index.ts b/packages/cli/src/modules/translations/index.ts new file mode 100644 index 0000000000..702b0f4f49 --- /dev/null +++ b/packages/cli/src/modules/translations/index.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2026 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 yargs from 'yargs'; +import { createCliPlugin } from '../../wiring/factory'; +import { lazy } from '../../lib/lazy'; +import { DEFAULT_MESSAGE_PATTERN } from './lib/messageFilePath'; + +export default createCliPlugin({ + pluginId: 'translations', + init: async reg => { + reg.addCommand({ + path: ['translations', 'export'], + description: + 'Export translation messages from an app and all of its frontend plugins to JSON files', + execute: async ({ args }) => { + const argv = await yargs() + .options({ + output: { + type: 'string', + default: 'translations', + description: + 'Output directory for exported messages and manifest', + }, + pattern: { + type: 'string', + default: DEFAULT_MESSAGE_PATTERN, + description: + 'File path pattern for message files, with {id} and {lang} placeholders', + }, + }) + .help() + .parse(args); + await lazy(() => import('./commands/export'), 'default')(argv); + }, + }); + + reg.addCommand({ + path: ['translations', 'import'], + description: + 'Generate translation resource wiring from translated JSON files', + execute: async ({ args }) => { + const argv = await yargs() + .options({ + input: { + type: 'string', + default: 'translations', + description: + 'Input directory containing the manifest and translated message files', + }, + output: { + type: 'string', + default: 'src/translations/resources.ts', + description: 'Output path for the generated wiring module', + }, + }) + .help() + .parse(args); + await lazy(() => import('./commands/import'), 'default')(argv); + }, + }); + }, +}); diff --git a/packages/cli/src/modules/translations/lib/discoverPackages.ts b/packages/cli/src/modules/translations/lib/discoverPackages.ts new file mode 100644 index 0000000000..c7a7602a7e --- /dev/null +++ b/packages/cli/src/modules/translations/lib/discoverPackages.ts @@ -0,0 +1,207 @@ +/* + * Copyright 2026 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 { + BackstagePackageJson, + PackageGraph, + PackageRoles, +} from '@backstage/cli-node'; +import { dirname, resolve as resolvePath } from 'node:path'; +import fs from 'fs-extra'; + +/** A discovered package with its entry points resolved to file paths. */ +export interface DiscoveredPackage { + /** The package name, e.g. '@backstage/plugin-org' */ + name: string; + /** The directory of the package */ + dir: string; + /** Map of export subpath (e.g. '.', './alpha') to the resolved file path */ + entryPoints: Map; +} + +/** + * Reads the package.json from the given directory and validates that it + * is a workspace package (not the repo root). + */ +export async function readTargetPackage( + packageDir: string, + repoRoot: string, +): Promise { + const packageJsonPath = resolvePath(packageDir, 'package.json'); + + if (!(await fs.pathExists(packageJsonPath))) { + throw new Error( + 'No package.json found in the current directory. ' + + 'The translations commands must be run from within a package directory.', + ); + } + + if (resolvePath(packageDir) === resolvePath(repoRoot)) { + throw new Error( + 'The translations commands must be run from within a package directory, ' + + 'not from the repository root. For example: cd packages/app && backstage-cli translations export', + ); + } + + return fs.readJson(packageJsonPath); +} + +/** + * Discovers frontend packages that are transitive dependencies of the given + * target package and resolves their entry point file paths. Walks both + * workspace packages (source) and npm-installed packages (declaration files). + */ +export async function discoverFrontendPackages( + targetPackageJson: BackstagePackageJson, + targetDir: string, +): Promise { + // Build a lookup of workspace packages for preferring source over dist + let workspaceByName: Map< + string, + { packageJson: BackstagePackageJson; dir: string } + >; + try { + const workspacePackages = await PackageGraph.listTargetPackages(); + workspaceByName = new Map( + workspacePackages.map(p => [p.packageJson.name, p]), + ); + } catch { + workspaceByName = new Map(); + } + + const visited = new Set(); + const result: DiscoveredPackage[] = []; + + async function visit( + packageJson: BackstagePackageJson, + pkgDir: string, + includeDevDeps: boolean, + ) { + const deps: Record = { + ...packageJson.dependencies, + ...(includeDevDeps ? packageJson.devDependencies ?? {} : {}), + }; + + for (const depName of Object.keys(deps)) { + if (visited.has(depName)) { + continue; + } + visited.add(depName); + + let depPkgJson: BackstagePackageJson; + let depDir: string; + let isWorkspace: boolean; + + // Prefer workspace package (has source files) over npm-installed + const workspacePkg = workspaceByName.get(depName); + if (workspacePkg) { + depPkgJson = workspacePkg.packageJson; + depDir = workspacePkg.dir; + isWorkspace = true; + } else { + try { + const pkgJsonPath = require.resolve(`${depName}/package.json`, { + paths: [pkgDir], + }); + depPkgJson = await fs.readJson(pkgJsonPath); + depDir = dirname(pkgJsonPath); + isWorkspace = false; + } catch { + continue; + } + } + + // Only recurse into Backstage ecosystem packages + if (!depPkgJson.backstage) { + continue; + } + + const role = depPkgJson.backstage?.role; + if (role && isFrontendRole(role)) { + const entryPoints = resolveEntryPoints(depPkgJson, depDir, isWorkspace); + if (entryPoints.size > 0) { + result.push({ name: depName, dir: depDir, entryPoints }); + } + } + + // Walk this package's production dependencies for transitive refs + await visit(depPkgJson, depDir, false); + } + } + + // Start from the target, including its devDependencies + await visit(targetPackageJson, targetDir, true); + + return result; +} + +/** + * Resolves the entry points of a package to absolute file paths. + * For workspace packages, prefers source entry points (import/default). + * For npm packages, prefers type declaration entry points (.d.ts). + */ +function resolveEntryPoints( + packageJson: BackstagePackageJson, + packageDir: string, + isWorkspace: boolean, +): Map { + const entryPoints = new Map(); + + const exports = (packageJson as any).exports as + | Record> + | undefined; + + if (exports) { + for (const [subpath, target] of Object.entries(exports)) { + if (subpath === './package.json') { + continue; + } + + let filePath: string | undefined; + if (typeof target === 'string') { + filePath = target; + } else if (isWorkspace) { + // Workspace: exports point to source .ts files + filePath = target?.import ?? target?.types ?? target?.default; + } else { + // npm: prefer .d.ts for type-based extraction + filePath = target?.types ?? target?.import ?? target?.default; + } + + if (typeof filePath === 'string') { + entryPoints.set(subpath, resolvePath(packageDir, filePath)); + } + } + } else { + // Fallback: prefer types for npm, source for workspace + const main = isWorkspace + ? packageJson.main ?? packageJson.types + : packageJson.types ?? packageJson.main; + if (main) { + entryPoints.set('.', resolvePath(packageDir, main)); + } + } + + return entryPoints; +} + +function isFrontendRole(role: string): boolean { + try { + return PackageRoles.getRoleInfo(role).platform === 'web'; + } catch { + return false; + } +} diff --git a/packages/cli/src/modules/translations/lib/extractTranslations.test.ts b/packages/cli/src/modules/translations/lib/extractTranslations.test.ts new file mode 100644 index 0000000000..27b67db052 --- /dev/null +++ b/packages/cli/src/modules/translations/lib/extractTranslations.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2026 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 { resolve as resolvePath } from 'node:path'; +import { + createTranslationProject, + extractTranslationRefsFromSourceFile, +} from './extractTranslations'; + +describe('extractTranslations', () => { + it('extracts translation refs from the org plugin', () => { + const project = createTranslationProject( + resolvePath(__dirname, '../../../../../../tsconfig.json'), + ); + + const sourceFile = project.addSourceFileAtPath( + resolvePath(__dirname, '../../../../../..', 'plugins/org/src/alpha.tsx'), + ); + + const refs = extractTranslationRefsFromSourceFile( + sourceFile, + '@backstage/plugin-org', + './alpha', + ); + + expect(refs).toHaveLength(1); + expect(refs[0]).toMatchObject({ + id: 'org', + packageName: '@backstage/plugin-org', + exportPath: './alpha', + exportName: 'orgTranslationRef', + }); + + expect(refs[0].messages).toBeDefined(); + expect(Object.keys(refs[0].messages)).not.toHaveLength(0); + + // Verify some well-known keys exist without pinning exact wording + expect(refs[0].messages).toHaveProperty(['groupProfileCard.groupNotFound']); + expect(refs[0].messages).toHaveProperty(['membersListCard.title']); + + // Verify interpolation placeholders are preserved + expect(refs[0].messages['membersListCard.subtitle']).toContain( + '{{groupName}}', + ); + }); + + it('ignores non-TranslationRef exports', () => { + const project = createTranslationProject( + resolvePath(__dirname, '../../../../../../tsconfig.json'), + ); + + // The main entry of org plugin exports components but no translation ref + const sourceFile = project.addSourceFileAtPath( + resolvePath(__dirname, '../../../../../..', 'plugins/org/src/index.ts'), + ); + + const refs = extractTranslationRefsFromSourceFile( + sourceFile, + '@backstage/plugin-org', + '.', + ); + + expect(refs).toHaveLength(0); + }); + + it('extracts from the test fixtures translation ref', () => { + const project = createTranslationProject( + resolvePath(__dirname, '../../../../../../tsconfig.json'), + ); + + const sourceFile = project.addSourceFileAtPath( + resolvePath( + __dirname, + '../../../../../..', + 'packages/frontend-plugin-api/src/translation/__fixtures__/refs.ts', + ), + ); + + const refs = extractTranslationRefsFromSourceFile( + sourceFile, + '@backstage/frontend-plugin-api', + '.', + ); + + expect(refs).toHaveLength(2); + + const counting = refs.find(r => r.id === 'counting'); + expect(counting).toMatchObject({ + messages: { + one: 'one', + two: 'two', + three: 'three', + }, + }); + + const fruits = refs.find(r => r.id === 'fruits'); + expect(fruits).toMatchObject({ + messages: { + apple: 'apple', + orange: 'orange', + }, + }); + }); +}); diff --git a/packages/cli/src/modules/translations/lib/extractTranslations.ts b/packages/cli/src/modules/translations/lib/extractTranslations.ts new file mode 100644 index 0000000000..6278a08598 --- /dev/null +++ b/packages/cli/src/modules/translations/lib/extractTranslations.ts @@ -0,0 +1,133 @@ +/* + * Copyright 2026 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 { Node, Project, SourceFile, Type, ts } from 'ts-morph'; + +/** Information about a discovered translation ref. */ +export interface TranslationRefInfo { + /** The ref ID, e.g. 'org' */ + id: string; + /** The package name, e.g. '@backstage/plugin-org' */ + packageName: string; + /** The subpath export where this ref is accessible, e.g. './alpha' or '.' */ + exportPath: string; + /** The exported symbol name, e.g. 'orgTranslationRef' */ + exportName: string; + /** Flattened message map: key -> default message string */ + messages: Record; +} + +/** + * Given a ts-morph SourceFile, finds all exported TranslationRef symbols + * and extracts their id and messages from the type system. + */ +export function extractTranslationRefsFromSourceFile( + sourceFile: SourceFile, + packageName: string, + exportPath: string, +): TranslationRefInfo[] { + const results: TranslationRefInfo[] = []; + + for (const exportSymbol of sourceFile.getExportSymbols()) { + const declarations = exportSymbol.getDeclarations(); + if (declarations.length === 0) { + continue; + } + + const declaration = declarations[0]; + const exportType = declaration.getType(); + + const refInfo = extractTranslationRefFromType(exportType, declaration); + if (!refInfo) { + continue; + } + + results.push({ + ...refInfo, + packageName, + exportPath, + exportName: exportSymbol.getName(), + }); + } + + return results; +} + +/** + * Checks whether a type is a TranslationRef by inspecting the $$type + * property on the target type, then extracts the id and messages from + * the type arguments of the generic instantiation. + */ +function extractTranslationRefFromType( + type: Type, + declaration: Node, +): Pick | undefined { + // Check the $$type property on the uninstantiated (target) type + const resolvedType = type.getTargetType() ?? type; + const $$typeProperty = resolvedType + .getProperties() + .find(p => p.getName() === '$$type'); + if (!$$typeProperty) { + return undefined; + } + const $$typeDecl = $$typeProperty.getValueDeclaration(); + if (!$$typeDecl) { + return undefined; + } + if (!$$typeDecl.getText().includes("'@backstage/TranslationRef'")) { + return undefined; + } + + // The type is TranslationRef - extract the type arguments + const typeArgs = type.getTypeArguments(); + if (typeArgs.length < 2) { + return undefined; + } + + const [idType, messagesType] = typeArgs; + + if (!idType.isStringLiteral()) { + return undefined; + } + const id = idType.getLiteralValueOrThrow() as string; + + // Extract messages from the TMessages type argument + const messages: Record = {}; + for (const messageProp of messagesType.getProperties()) { + const key = messageProp.getName(); + // Resolve the property type in the context of the declaration + const propType = messageProp.getTypeAtLocation(declaration); + if (propType.isStringLiteral()) { + messages[key] = propType.getLiteralValueOrThrow() as string; + } + } + + if (Object.keys(messages).length === 0) { + return undefined; + } + + return { id, messages }; +} + +/** + * Creates a ts-morph Project using the target repo's tsconfig.json. + */ +export function createTranslationProject(tsconfigPath: string): Project { + return new Project({ + tsConfigFilePath: tsconfigPath, + skipAddingFilesFromTsConfig: true, + }); +} diff --git a/packages/cli/src/modules/translations/lib/messageFilePath.test.ts b/packages/cli/src/modules/translations/lib/messageFilePath.test.ts new file mode 100644 index 0000000000..4c276e114c --- /dev/null +++ b/packages/cli/src/modules/translations/lib/messageFilePath.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright 2026 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 { + formatMessagePath, + createMessagePathParser, + messagePatternToGlob, + patternHasSubdirectories, + DEFAULT_MESSAGE_PATTERN, +} from './messageFilePath'; + +describe('messageFilePath', () => { + describe('formatMessagePath', () => { + it('formats the default pattern', () => { + expect(formatMessagePath(DEFAULT_MESSAGE_PATTERN, 'org', 'en')).toBe( + 'messages/org.en.json', + ); + }); + + it('formats with a different language', () => { + expect(formatMessagePath(DEFAULT_MESSAGE_PATTERN, 'catalog', 'sv')).toBe( + 'messages/catalog.sv.json', + ); + }); + + it('formats a language-directory pattern', () => { + expect(formatMessagePath('{lang}/{id}.json', 'org', 'sv')).toBe( + 'sv/org.json', + ); + }); + + it('formats a pattern with lang first in filename', () => { + expect(formatMessagePath('{lang}.{id}.json', 'org', 'de')).toBe( + 'de.org.json', + ); + }); + }); + + describe('createMessagePathParser', () => { + it('parses the default pattern', () => { + const parse = createMessagePathParser(DEFAULT_MESSAGE_PATTERN); + expect(parse('messages/org.en.json')).toEqual({ id: 'org', lang: 'en' }); + }); + + it('parses dotted ref IDs in the default pattern', () => { + const parse = createMessagePathParser(DEFAULT_MESSAGE_PATTERN); + expect(parse('messages/plugin.notifications.sv.json')).toEqual({ + id: 'plugin.notifications', + lang: 'sv', + }); + }); + + it('parses a language-directory pattern', () => { + const parse = createMessagePathParser('{lang}/{id}.json'); + expect(parse('sv/org.json')).toEqual({ id: 'org', lang: 'sv' }); + }); + + it('returns undefined for non-matching paths', () => { + const parse = createMessagePathParser(DEFAULT_MESSAGE_PATTERN); + expect(parse('not-a-match.txt')).toBeUndefined(); + expect(parse('other/org.en.json')).toBeUndefined(); + }); + + it('returns undefined for invalid language code', () => { + const parse = createMessagePathParser('{lang}/{id}.json'); + expect(parse('123/org.json')).toBeUndefined(); + }); + + it('throws on pattern missing {id}', () => { + expect(() => createMessagePathParser('{lang}.json')).toThrow( + 'must contain {id}', + ); + }); + + it('throws on pattern missing {lang}', () => { + expect(() => createMessagePathParser('{id}.json')).toThrow( + 'must contain {lang}', + ); + }); + + it('throws on pattern not ending with .json', () => { + expect(() => createMessagePathParser('{id}.{lang}.yaml')).toThrow( + 'must end with .json', + ); + }); + }); + + describe('messagePatternToGlob', () => { + it('converts the default pattern', () => { + expect(messagePatternToGlob(DEFAULT_MESSAGE_PATTERN)).toBe( + 'messages/*.*.json', + ); + }); + + it('converts a language-directory pattern', () => { + expect(messagePatternToGlob('{lang}/{id}.json')).toBe('*/*.json'); + }); + }); + + describe('patternHasSubdirectories', () => { + it('returns true for the default pattern', () => { + expect(patternHasSubdirectories(DEFAULT_MESSAGE_PATTERN)).toBe(true); + }); + + it('returns true for patterns with directories', () => { + expect(patternHasSubdirectories('{lang}/{id}.json')).toBe(true); + }); + }); +}); diff --git a/packages/cli/src/modules/translations/lib/messageFilePath.ts b/packages/cli/src/modules/translations/lib/messageFilePath.ts new file mode 100644 index 0000000000..eb3dc8ea5c --- /dev/null +++ b/packages/cli/src/modules/translations/lib/messageFilePath.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2026 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. + */ + +// The default language for exported translation messages. +export const DEFAULT_LANGUAGE = 'en'; + +// Default file path pattern for translation message files relative to the +// translations directory. Supported placeholders: {id} and {lang}. +export const DEFAULT_MESSAGE_PATTERN = 'messages/{id}.{lang}.json'; + +/** Formats a message file pattern into a concrete relative path. */ +export function formatMessagePath( + pattern: string, + id: string, + lang: string, +): string { + return pattern.replace(/\{id\}/g, id).replace(/\{lang\}/g, lang); +} + +/** Creates a parser that extracts id and lang from a relative file path. */ +export function createMessagePathParser( + pattern: string, +): (relativePath: string) => { id: string; lang: string } | undefined { + validatePattern(pattern); + + // Build a regex from the pattern by escaping special chars and replacing + // {id} and {lang} with named capture groups. + const escaped = pattern + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + .replace(/\\{id\\}/g, '(?[^/]+)') + .replace(/\\{lang\\}/g, '(?[a-z]{2})'); + + const regex = new RegExp(`^${escaped}$`); + + return (relPath: string) => { + const match = relPath.match(regex); + if (!match?.groups) { + return undefined; + } + return { id: match.groups.id, lang: match.groups.lang }; + }; +} + +/** Converts a message pattern into a glob string for discovering files. */ +export function messagePatternToGlob(pattern: string): string { + return pattern.replace(/\{id\}/g, '*').replace(/\{lang\}/g, '*'); +} + +/** Returns whether the pattern produces paths with subdirectories. */ +export function patternHasSubdirectories(pattern: string): boolean { + return pattern.includes('/'); +} + +export function validatePattern(pattern: string) { + if (!pattern.includes('{id}')) { + throw new Error( + `Invalid message file pattern: must contain {id} placeholder. Got: ${pattern}`, + ); + } + if (!pattern.includes('{lang}')) { + throw new Error( + `Invalid message file pattern: must contain {lang} placeholder. Got: ${pattern}`, + ); + } + if (!pattern.endsWith('.json')) { + throw new Error( + `Invalid message file pattern: must end with .json. Got: ${pattern}`, + ); + } +} diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 77b4d0f9cb..38ccd0f874 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/codemods +## 0.1.55-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + ## 0.1.54 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 6a8a464a37..c531c4ee69 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/codemods", - "version": "0.1.54", + "version": "0.1.55-next.0", "description": "A collection of codemods for Backstage projects", "backstage": { "role": "cli" diff --git a/packages/codemods/src/action.ts b/packages/codemods/src/action.ts index 2c7b9b8d01..7a6c241497 100644 --- a/packages/codemods/src/action.ts +++ b/packages/codemods/src/action.ts @@ -16,17 +16,16 @@ import { relative as relativePath } from 'node:path'; import { OptionValues } from 'commander'; -import { findPaths, run } from '@backstage/cli-common'; +import { findOwnPaths, run } from '@backstage/cli-common'; import { platform } from 'node:os'; -// eslint-disable-next-line no-restricted-syntax -const paths = findPaths(__dirname); - export function createCodemodAction(name: string) { return async (dirs: string[], opts: OptionValues) => { + // eslint-disable-next-line no-restricted-syntax + const paths = findOwnPaths(__dirname); const transformPath = relativePath( process.cwd(), - paths.resolveOwn('transforms', `${name}.js`), + paths.resolve('transforms', `${name}.js`), ); const args = [ diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 97831338a6..22a9f2c76f 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/config-loader +## 1.10.9-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 1.10.8 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 985bdef1a5..18b16787ab 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config-loader", - "version": "1.10.8", + "version": "1.10.9-next.0", "description": "Config loading functionality used by Backstage backend, and CLI", "backstage": { "role": "node-library" diff --git a/packages/config-loader/report.api.md b/packages/config-loader/report.api.md index e2741d609c..a13904f14b 100644 --- a/packages/config-loader/report.api.md +++ b/packages/config-loader/report.api.md @@ -221,7 +221,7 @@ export interface MutableConfigSourceOptions { } // @public -export type Parser = ({ contents }: { contents: string }) => Promise<{ +export type Parser = (input: { contents: string }) => Promise<{ result?: JsonObject; }>; diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index 2133eccc29..153da69dbd 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -27,7 +27,7 @@ import { } from './RemoteConfigSource'; import { ConfigSource, SubstitutionFunc } from './types'; import { ObservableConfigProxy } from './ObservableConfigProxy'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; /** * A target to read configuration from. @@ -157,7 +157,7 @@ export class ConfigSources { static defaultForTargets( options: ConfigSourcesDefaultForTargetsOptions, ): ConfigSource { - const rootDir = options.rootDir ?? findPaths(process.cwd()).targetRoot; + const rootDir = options.rootDir ?? targetPaths.rootDir; const argSources = options.targets.map(arg => { if (arg.type === 'url') { diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index b9d741ea9c..42d0581f64 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-app-api +## 1.19.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + ## 1.19.5 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 242db797ad..231ee0f4c1 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-app-api", - "version": "1.19.5", + "version": "1.19.6-next.0", "description": "Core app API used by Backstage apps", "backstage": { "role": "web-library" diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 7a45beca2d..9b6e2a4576 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/core-compat-api +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + ## 0.5.8 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 1a03a36bd2..3a27730600 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.5.8", + "version": "0.5.9-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index a9b0d68ddf..4407f55bd7 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-components +## 0.18.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/version-bridge@1.0.12 + ## 0.18.7 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 0ba7a89ceb..02f9b782c1 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-components", - "version": "0.18.7", + "version": "0.18.8-next.0", "description": "Core components used by Backstage plugins and apps", "backstage": { "role": "web-library" diff --git a/packages/core-components/report.api.md b/packages/core-components/report.api.md index 5e842929e6..0cd8a7d866 100644 --- a/packages/core-components/report.api.md +++ b/packages/core-components/report.api.md @@ -652,15 +652,7 @@ export type HorizontalScrollGridClassKey = export type IconComponentProps = ComponentProps; // @public (undocumented) -export function IconLinkVertical({ - color, - disabled, - href, - icon, - label, - onClick, - title, -}: IconLinkVerticalProps): JSX_2.Element; +export function IconLinkVertical(input: IconLinkVerticalProps): JSX_2.Element; // @public (undocumented) export type IconLinkVerticalClassKey = diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index eebb94a45f..61c5d409c2 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-plugin-api +## 1.12.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + ## 1.12.3 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 202f532b95..d199bfa8da 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-plugin-api", - "version": "1.12.3", + "version": "1.12.4-next.0", "description": "Core API used by Backstage plugins", "backstage": { "role": "web-library" diff --git a/packages/core-plugin-api/report.api.md b/packages/core-plugin-api/report.api.md index dc5a042488..41887f7e63 100644 --- a/packages/core-plugin-api/report.api.md +++ b/packages/core-plugin-api/report.api.md @@ -508,7 +508,7 @@ export { ProfileInfoApi }; // @public export type RouteFunc = ( - ...[params]: Params extends undefined ? readonly [] : readonly [Params] + ...input: Params extends undefined ? readonly [] : readonly [Params] ) => string; // @public diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 39c6951d85..834d31aef9 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/create-app +## 0.7.10-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + ## 0.7.9 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 4841169251..31a6e5347d 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/create-app", - "version": "0.7.9", + "version": "0.7.10-next.0", "description": "A CLI that helps you create your own Backstage app", "backstage": { "role": "cli" diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index c854867de6..c38186b1d8 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -19,12 +19,17 @@ import path from 'node:path'; import { Command } from 'commander'; import * as tasks from './lib/tasks'; import createApp from './createApp'; -import { findPaths } from '@backstage/cli-common'; +import { findOwnPaths, targetPaths } from '@backstage/cli-common'; import { tmpdir } from 'node:os'; import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; jest.mock('./lib/tasks'); +const MOCK_TARGET_DIR = '/mock/target-dir'; +const MOCK_TARGET_ROOT = '/mock/target-root'; +overrideTargetPaths({ dir: MOCK_TARGET_DIR, rootDir: MOCK_TARGET_ROOT }); + // By mocking this the filesystem mocks won't mess with reading all of the package.jsons jest.mock('./lib/versions', () => ({ packageVersions: { root: '1.0.0' }, @@ -64,12 +69,7 @@ describe('command entrypoint', () => { expect(tryInitGitRepositoryMock).toHaveBeenCalled(); expect(templatingMock).toHaveBeenCalled(); expect(templatingMock.mock.lastCall?.[0]).toEqual( - findPaths(__dirname).resolveTarget( - 'packages', - 'create-app', - 'templates', - 'default-app', - ), + findOwnPaths(__dirname).resolve('templates/default-app'), ); expect(templatingMock.mock.lastCall?.[1]).toContain( path.join(tmpdir(), 'MyApp'), @@ -85,12 +85,7 @@ describe('command entrypoint', () => { expect(tryInitGitRepositoryMock).toHaveBeenCalled(); expect(templatingMock).toHaveBeenCalled(); expect(templatingMock.mock.lastCall?.[0]).toEqual( - findPaths(__dirname).resolveTarget( - 'packages', - 'create-app', - 'templates', - 'default-app', - ), + findOwnPaths(__dirname).resolve('templates/default-app'), ); expect(templatingMock.mock.lastCall?.[1]).toEqual('myDirectory'); expect(buildAppMock).toHaveBeenCalled(); @@ -103,12 +98,7 @@ describe('command entrypoint', () => { expect(tryInitGitRepositoryMock).toHaveBeenCalled(); expect(templatingMock).toHaveBeenCalled(); expect(templatingMock.mock.lastCall?.[0]).toEqual( - findPaths(__dirname).resolveTarget( - 'packages', - 'create-app', - 'templates', - 'next-app', - ), + findOwnPaths(__dirname).resolve('templates/next-app'), ); expect(templatingMock.mock.lastCall?.[1]).toContain( path.join(tmpdir(), 'MyApp'), @@ -127,7 +117,7 @@ describe('command entrypoint', () => { expect(tryInitGitRepositoryMock).toHaveBeenCalled(); expect(templatingMock).toHaveBeenCalled(); expect(templatingMock.mock.lastCall?.[0]).toEqual( - findPaths(__dirname).resolveTarget('templateDirectory'), + targetPaths.resolve('templateDirectory'), ); expect(templatingMock.mock.lastCall?.[1]).toEqual('myDirectory'); expect(buildAppMock).toHaveBeenCalled(); diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index 11e5503899..64db2e52ab 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -18,7 +18,7 @@ import chalk from 'chalk'; import { OptionValues } from 'commander'; import inquirer, { Answers } from 'inquirer'; import { resolve as resolvePath } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths, findOwnPaths } from '@backstage/cli-common'; import os from 'node:os'; import fs from 'fs-extra'; import { @@ -36,8 +36,6 @@ import { const DEFAULT_BRANCH = 'master'; export default async (opts: OptionValues): Promise => { - /* eslint-disable-next-line no-restricted-syntax */ - const paths = findPaths(__dirname); const answers: Answers = await inquirer.prompt([ { type: 'input', @@ -66,20 +64,22 @@ export default async (opts: OptionValues): Promise => { ]); // Pick the built-in template based on the --next flag + /* eslint-disable-next-line no-restricted-syntax */ + const ownPaths = findOwnPaths(__dirname); const builtInTemplate = opts.next - ? paths.resolveOwn('templates/next-app') - : paths.resolveOwn('templates/default-app'); + ? ownPaths.resolve('templates/next-app') + : ownPaths.resolve('templates/default-app'); // Use `--template-path` argument as template when specified. Otherwise, use the default template. const templateDir = opts.templatePath - ? paths.resolveTarget(opts.templatePath) + ? targetPaths.resolve(opts.templatePath) : builtInTemplate; // Use `--path` argument as application directory when specified, otherwise // create a directory using `answers.name` const appDir = opts.path - ? resolvePath(paths.targetDir, opts.path) - : resolvePath(paths.targetDir, answers.name); + ? resolvePath(targetPaths.dir, opts.path) + : resolvePath(targetPaths.dir, answers.name); Task.log(); Task.log('Creating the app...'); @@ -102,7 +102,7 @@ export default async (opts: OptionValues): Promise => { // Template to temporary location, and then move files Task.section('Checking if the directory is available'); - await checkAppExistsTask(paths.targetDir, answers.name); + await checkAppExistsTask(targetPaths.dir, answers.name); Task.section('Creating a temporary app directory'); const tempDir = await fs.mkdtemp(resolvePath(os.tmpdir(), answers.name)); diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 51957793b4..0ce067fe4f 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/dev-utils +## 1.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/app-defaults@1.7.6-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + ## 1.1.20 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0f59ec8d27..9f83d94cd1 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.1.20", + "version": "1.1.21-next.0", "description": "Utilities for developing Backstage plugins.", "backstage": { "role": "web-library" diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 7fbdca51c4..525bc47606 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/create-app@0.7.10-next.0 + - @backstage/errors@1.2.7 + ## 0.2.37 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 1a2142d6e9..782fea0710 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,6 +1,6 @@ { "name": "e2e-test", - "version": "0.2.37", + "version": "0.2.38-next.0", "description": "E2E test for verifying Backstage packages", "backstage": { "role": "cli" diff --git a/packages/e2e-test/src/commands/runCommand.ts b/packages/e2e-test/src/commands/runCommand.ts index f0701d0e5d..da39351400 100644 --- a/packages/e2e-test/src/commands/runCommand.ts +++ b/packages/e2e-test/src/commands/runCommand.ts @@ -27,11 +27,11 @@ import { waitFor, print } from '../lib/helpers'; import mysql from 'mysql2/promise'; import pgtools from 'pgtools'; -import { findPaths, runOutput, run } from '@backstage/cli-common'; import { OptionValues } from 'commander'; +import { findOwnPaths, runOutput, run } from '@backstage/cli-common'; -// eslint-disable-next-line no-restricted-syntax -const paths = findPaths(__dirname); +/* eslint-disable-next-line no-restricted-syntax */ +const ownPaths = findOwnPaths(__dirname); const templatePackagePaths = [ 'packages/cli/templates/frontend-plugin/package.json.hbs', @@ -138,7 +138,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { } for (const pkgJsonPath of templatePackagePaths) { - const jsonPath = paths.resolveOwnRoot(pkgJsonPath); + const jsonPath = ownPaths.resolveRoot(pkgJsonPath); const pkgTemplate = await fs.readFile(jsonPath, 'utf8'); const pkg = JSON.parse( handlebars.compile(pkgTemplate)( @@ -196,7 +196,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { print('Pinning yarn version in workspace'); await pinYarnVersion(workspaceDir); - const yarnPatchesPath = paths.resolveOwnRoot('.yarn/patches'); + const yarnPatchesPath = ownPaths.resolveRoot('.yarn/patches'); if (await fs.pathExists(yarnPatchesPath)) { print('Copying yarn patches'); await fs.copy(yarnPatchesPath, resolvePath(workspaceDir, '.yarn/patches')); @@ -214,7 +214,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { * Pin the yarn version in a directory to the one we're using in the Backstage repo */ async function pinYarnVersion(dir: string) { - const yarnRc = await fs.readFile(paths.resolveOwnRoot('.yarnrc.yml'), 'utf8'); + const yarnRc = await fs.readFile(ownPaths.resolveRoot('.yarnrc.yml'), 'utf8'); const yarnRcLines = yarnRc.split(/\r?\n/); const yarnPathLine = yarnRcLines.find(line => line.startsWith('yarnPath:')); if (!yarnPathLine) { @@ -225,8 +225,8 @@ async function pinYarnVersion(dir: string) { throw new Error(`Invalid 'yarnPath' in ${yarnRc}`); } const [, localYarnPath] = match; - const yarnPath = paths.resolveOwnRoot(localYarnPath); - const yarnPluginPath = paths.resolveOwnRoot( + const yarnPath = ownPaths.resolveRoot(localYarnPath); + const yarnPluginPath = ownPaths.resolveRoot( localYarnPath, '../../plugins/@yarnpkg/plugin-workspace-tools.cjs', ); @@ -328,7 +328,7 @@ async function createApp( */ async function overrideYarnLockSeed(appDir: string) { const content = await fs.readFile( - paths.resolveOwnRoot('packages/create-app/seed-yarn.lock'), + ownPaths.resolveRoot('packages/create-app/seed-yarn.lock'), 'utf8', ); const trimmedContent = content diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index fa9e3d5c84..71b385bcfe 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/eslint-plugin +## 0.2.2-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 + ## 0.2.1 ### Patch Changes diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index bfc3996ee3..89e08206ce 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/eslint-plugin", - "version": "0.2.1", + "version": "0.2.2-next.0", "description": "Backstage ESLint plugin", "publishConfig": { "access": "public" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 0ca0df5ac2..d35e1a6dfc 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/frontend-app-api +## 0.15.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + ## 0.15.0 ### Minor Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index b3e978990c..997c3c6110 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.15.0", + "version": "0.15.1-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-defaults/CHANGELOG.md b/packages/frontend-defaults/CHANGELOG.md index b157fd2907..9168af715c 100644 --- a/packages/frontend-defaults/CHANGELOG.md +++ b/packages/frontend-defaults/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/frontend-defaults +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/errors@1.2.7 + - @backstage/frontend-app-api@0.15.1-next.0 + ## 0.4.0 ### Minor Changes diff --git a/packages/frontend-defaults/package.json b/packages/frontend-defaults/package.json index 26411b6d98..92951da7c5 100644 --- a/packages/frontend-defaults/package.json +++ b/packages/frontend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-defaults", - "version": "0.4.0", + "version": "0.4.1-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-dynamic-feature-loader/CHANGELOG.md b/packages/frontend-dynamic-feature-loader/CHANGELOG.md index 1525b390d8..d29ecadc52 100644 --- a/packages/frontend-dynamic-feature-loader/CHANGELOG.md +++ b/packages/frontend-dynamic-feature-loader/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/frontend-dynamic-feature-loader +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/config@1.3.6 + - @backstage/module-federation-common@0.1.0 + ## 0.1.9 ### Patch Changes diff --git a/packages/frontend-dynamic-feature-loader/package.json b/packages/frontend-dynamic-feature-loader/package.json index 49007bdd39..36480783db 100644 --- a/packages/frontend-dynamic-feature-loader/package.json +++ b/packages/frontend-dynamic-feature-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-dynamic-feature-loader", - "version": "0.1.9", + "version": "0.1.10-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-internal/CHANGELOG.md b/packages/frontend-internal/CHANGELOG.md index 958c0f3fb6..4005f83616 100644 --- a/packages/frontend-internal/CHANGELOG.md +++ b/packages/frontend-internal/CHANGELOG.md @@ -1,5 +1,14 @@ # @internal/frontend +## 0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + ## 0.0.17 ### Patch Changes diff --git a/packages/frontend-internal/package.json b/packages/frontend-internal/package.json index 57b4eba729..cab3779acd 100644 --- a/packages/frontend-internal/package.json +++ b/packages/frontend-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/frontend", - "version": "0.0.17", + "version": "0.0.18-next.0", "backstage": { "role": "web-library", "inline": true diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index 7238a08512..ed6349d9e4 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/frontend-plugin-api +## 0.14.2-next.0 + +### Patch Changes + +- 9c81af9: Made the `pluginId` property optional in the `FrontendFeature` type, allowing plugins published against older versions of the framework to be used without type errors. +- Updated dependencies + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + ## 0.14.0 ### Minor Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 7b4ae8f36b..5002ed98a0 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.14.0", + "version": "0.14.2-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/report.api.md b/packages/frontend-plugin-api/report.api.md index 1909b1deef..c83511fc47 100644 --- a/packages/frontend-plugin-api/report.api.md +++ b/packages/frontend-plugin-api/report.api.md @@ -1938,9 +1938,7 @@ export type ResolvedExtensionInputs< // @public export type RouteFunc = ( - ...[params]: TParams extends undefined - ? readonly [] - : readonly [params: TParams] + ...input: TParams extends undefined ? readonly [] : readonly [params: TParams] ) => string; // @public @@ -2130,7 +2128,7 @@ export type TranslationFunction< ? { ( key: TKey, - ...[args]: TranslationFunctionOptions< + ...input: TranslationFunctionOptions< NestedMessageKeys, PluralKeys, IMessages, @@ -2139,7 +2137,7 @@ export type TranslationFunction< ): IMessages[TKey]; ( key: TKey, - ...[args]: TranslationFunctionOptions< + ...input: TranslationFunctionOptions< NestedMessageKeys, PluralKeys, IMessages, diff --git a/packages/frontend-plugin-api/src/apis/definitions/TranslationApi.ts b/packages/frontend-plugin-api/src/apis/definitions/TranslationApi.ts index 2578eaf7c4..b569800e3e 100644 --- a/packages/frontend-plugin-api/src/apis/definitions/TranslationApi.ts +++ b/packages/frontend-plugin-api/src/apis/definitions/TranslationApi.ts @@ -22,7 +22,7 @@ import { JSX } from 'react'; /** * Base translation options. * - * @alpha + * @ignore */ interface BaseOptions { interpolation?: { diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 040cdac005..74e112c067 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/frontend-test-utils +## 0.5.1-next.0 + +### Patch Changes + +- 909c742: Switched `MockTranslationApi` and related test utility imports from `@backstage/core-plugin-api/alpha` to the stable `@backstage/frontend-plugin-api` export. The `TranslationApi` type in the API report is now sourced from a single package. This has no effect on runtime behavior. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-app@0.4.1-next.0 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/frontend-app-api@0.15.1-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.5.0 ### Minor Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 6e7f487654..aa35b3dff9 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.5.0", + "version": "0.5.1-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-test-utils/report.api.md b/packages/frontend-test-utils/report.api.md index 748eee15d3..1cba02f393 100644 --- a/packages/frontend-test-utils/report.api.md +++ b/packages/frontend-test-utils/report.api.md @@ -46,10 +46,9 @@ import { RouteRef } from '@backstage/frontend-plugin-api'; import { StorageApi } from '@backstage/core-plugin-api'; import { StorageApi as StorageApi_2 } from '@backstage/frontend-plugin-api'; import { StorageValueSnapshot } from '@backstage/core-plugin-api'; -import { TranslationApi } from '@backstage/core-plugin-api/alpha'; -import { TranslationApi as TranslationApi_2 } from '@backstage/frontend-plugin-api'; -import { TranslationRef } from '@backstage/core-plugin-api/alpha'; -import { TranslationSnapshot } from '@backstage/core-plugin-api/alpha'; +import { TranslationApi } from '@backstage/frontend-plugin-api'; +import { TranslationRef } from '@backstage/frontend-plugin-api'; +import { TranslationSnapshot } from '@backstage/frontend-plugin-api'; import { withLogCollector } from '@backstage/test-utils'; // @public @@ -265,17 +264,17 @@ export namespace mockApis { ) => ApiMock; } export function translation(): MockTranslationApi & - MockWithApiFactory; + MockWithApiFactory; export namespace translation { const mock: ( - partialImpl?: Partial | undefined, - ) => ApiMock; + partialImpl?: Partial | undefined, + ) => ApiMock; } } // @public export class MockConfigApi implements ConfigApi { - constructor({ data }: { data: JsonObject }); + constructor(input: { data: JsonObject }); get(key?: string): T; getBoolean(key: string): boolean; getConfig(key: string): Config; diff --git a/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.test.tsx b/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.test.tsx index 4bee969a6d..8c9a15e677 100644 --- a/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.test.tsx +++ b/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { createTranslationRef } from '@backstage/frontend-plugin-api'; import { MockTranslationApi } from './MockTranslationApi'; describe('MockTranslationApi', () => { diff --git a/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.ts b/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.ts index d5fa29ea73..f5112ca175 100644 --- a/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.ts +++ b/packages/frontend-test-utils/src/apis/TranslationApi/MockTranslationApi.ts @@ -18,7 +18,7 @@ import { TranslationApi, TranslationRef, TranslationSnapshot, -} from '@backstage/core-plugin-api/alpha'; +} from '@backstage/frontend-plugin-api'; import { createInstance as createI18n, type i18n as I18n } from 'i18next'; import ObservableImpl from 'zen-observable'; @@ -32,7 +32,7 @@ import { JsxInterpolator } from '../../../../core-app-api/src/apis/implementatio const DEFAULT_LANGUAGE = 'en'; /** - * Mock implementation of {@link @backstage/core-plugin-api/alpha#TranslationApi}. + * Mock implementation of {@link @backstage/frontend-plugin-api#TranslationApi}. * * @public */ diff --git a/packages/frontend-test-utils/src/apis/mockApis.ts b/packages/frontend-test-utils/src/apis/mockApis.ts index 9e3dce1e3a..78d5c2bf19 100644 --- a/packages/frontend-test-utils/src/apis/mockApis.ts +++ b/packages/frontend-test-utils/src/apis/mockApis.ts @@ -201,7 +201,7 @@ export namespace mockApis { } /** - * Fake implementation of {@link @backstage/core-plugin-api/alpha#TranslationApi}. + * Fake implementation of {@link @backstage/frontend-plugin-api#TranslationApi}. * By default returns the default translation. * * @public @@ -216,14 +216,14 @@ export namespace mockApis { } /** - * Mock helpers for {@link @backstage/core-plugin-api/alpha#TranslationApi}. + * Mock helpers for {@link @backstage/frontend-plugin-api#TranslationApi}. * * @see {@link @backstage/frontend-plugin-api#mockApis.translation} * @public */ export namespace translation { /** - * Creates a mock of {@link @backstage/core-plugin-api/alpha#TranslationApi}. + * Creates a mock of {@link @backstage/frontend-plugin-api#TranslationApi}. * * @public */ diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index c5b3247473..a038cd3ac5 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 1.2.15 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index a2c4cd7e78..b8a7f6a678 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.2.15", + "version": "1.2.16-next.0", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 888613617f..947f559196 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.21.0-next.0 + +### Minor Changes + +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + ## 1.20.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index c3e0b07340..8f5bfd3e8b 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.20.0", + "version": "1.21.0-next.0", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 8f1d51361f..67ebd2fec6 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/repo-tools +## 0.16.6-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- 2a51546: Fixed prettier existence checks in OpenAPI commands to use `fs.pathExists` instead of checking the resolved path string, which was always truthy. +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- 18a946c: Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/cli-node@0.2.19-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + ## 0.16.4 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 57632eedd7..cca2b5a86a 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/repo-tools", - "version": "0.16.4", + "version": "0.16.6-next.0", "description": "CLI for Backstage repo tooling ", "backstage": { "role": "cli" @@ -52,7 +52,7 @@ "@electric-sql/pglite": "^0.3.0", "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.28.1", - "@microsoft/api-extractor": "^7.55.1", + "@microsoft/api-extractor": "^7.57.3", "@openapitools/openapi-generator-cli": "^2.7.0", "@prettier/sync": "^0.6.1", "@stoplight/spectral-core": "^1.18.0", diff --git a/packages/repo-tools/src/commands/api-reports/api-reports/createTemporaryTsConfig.ts b/packages/repo-tools/src/commands/api-reports/api-reports/createTemporaryTsConfig.ts index 028466dbab..5cf62f8bac 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports/createTemporaryTsConfig.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports/createTemporaryTsConfig.ts @@ -16,10 +16,10 @@ import fs from 'fs-extra'; import { join } from 'node:path'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export async function createTemporaryTsConfig(includedPackageDirs: string[]) { - const path = cliPaths.resolveTargetRoot('tsconfig.tmp.json'); + const path = targetPaths.resolveRoot('tsconfig.tmp.json'); process.once('exit', () => { fs.removeSync(path); diff --git a/packages/repo-tools/src/commands/api-reports/api-reports/generateTypeDeclarations.ts b/packages/repo-tools/src/commands/api-reports/api-reports/generateTypeDeclarations.ts index a51c9ed17b..1165c24a77 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports/generateTypeDeclarations.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports/generateTypeDeclarations.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { run, ExitCodeError } from '@backstage/cli-common'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; /** * Generates the TypeScript declaration files for the specified project, using the provided `tsconfig.json` file. @@ -29,7 +29,7 @@ import { paths as cliPaths } from '../../../lib/paths'; * @returns {Promise} A promise that resolves when the declaration files have been generated. */ export async function generateTypeDeclarations(tsconfigFilePath: string) { - await fs.remove(cliPaths.resolveTargetRoot('dist-types')); + await fs.remove(targetPaths.resolveRoot('dist-types')); try { await run( [ @@ -43,7 +43,7 @@ export async function generateTypeDeclarations(tsconfigFilePath: string) { 'false', ], { - cwd: cliPaths.targetRoot, + cwd: targetPaths.rootDir, }, ).waitForExit(); } catch (error) { diff --git a/packages/repo-tools/src/commands/api-reports/api-reports/patchApiReportGeneration.ts b/packages/repo-tools/src/commands/api-reports/api-reports/patchApiReportGeneration.ts index 40778594ec..3ac3eef99b 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports/patchApiReportGeneration.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports/patchApiReportGeneration.ts @@ -18,7 +18,7 @@ import { ExtractorMessage } from '@microsoft/api-extractor'; import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclaration'; import { Program } from 'typescript'; import { tryRunPrettier } from '../common'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; let applied = false; @@ -162,7 +162,7 @@ export function patchApiReportGeneration() { parser: 'markdown', // We need a real-looking filepath for proper config resolution, not just a directory // Ideally, the real filepath would be better, but it would require too much patching, for very little gain. - filepath: `${cliPaths.targetRoot}/report.api.md`, + filepath: `${targetPaths.rootDir}/report.api.md`, }); }; } diff --git a/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.test.ts b/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.test.ts new file mode 100644 index 0000000000..c99bdb90eb --- /dev/null +++ b/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.test.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2026 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 { TSDocTagSyntaxKind } from '@microsoft/tsdoc'; +import { getTsDocConfig } from './runApiExtraction'; + +describe('getTsDocConfig', () => { + it('should load the base TSDoc config from api-extractor', async () => { + const config = await getTsDocConfig(); + + expect(config).toBeDefined(); + expect(config.filePath).toContain('tsdoc-base.json'); + }); + + it('should add @ignore tag definition with ModifierTag syntax', async () => { + const config = await getTsDocConfig(); + + const ignoreTag = config.tagDefinitions.find( + tag => tag.tagName === '@ignore', + ); + expect(ignoreTag).toBeDefined(); + expect(ignoreTag?.tagName).toBe('@ignore'); + expect(ignoreTag?.syntaxKind).toBe(TSDocTagSyntaxKind.ModifierTag); + }); + + it('should add @config tag definition with BlockTag syntax', async () => { + const config = await getTsDocConfig(); + + const configTag = config.tagDefinitions.find( + tag => tag.tagName === '@config', + ); + expect(configTag).toBeDefined(); + expect(configTag?.tagName).toBe('@config'); + expect(configTag?.syntaxKind).toBe(TSDocTagSyntaxKind.BlockTag); + }); + + it('should enable support for @ignore tag', async () => { + const config = await getTsDocConfig(); + + expect(config.supportForTags.get('@ignore')).toBe(true); + }); + + it('should enable support for @config tag', async () => { + const config = await getTsDocConfig(); + + expect(config.supportForTags.get('@config')).toBe(true); + }); +}); diff --git a/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.ts b/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.ts index da8278f9ad..787a2cb3f4 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.ts @@ -31,13 +31,11 @@ import { resolve as resolvePath, } from 'node:path'; import { getPackageExportDetails } from '../../../lib/getPackageExportDetails'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import { logApiReportInstructions } from '../common'; import { patchApiReportGeneration } from './patchApiReportGeneration'; -const tmpDir = cliPaths.resolveTargetRoot( - './node_modules/.cache/api-extractor', -); +const tmpDir = targetPaths.resolveRoot('./node_modules/.cache/api-extractor'); export async function countApiReportWarnings(reportPath: string) { try { @@ -100,7 +98,7 @@ async function findPackageEntryPoints(packageDirs: string[]): Promise< return Promise.all( packageDirs.map(async packageDir => { const pkg = await fs.readJson( - cliPaths.resolveTargetRoot(packageDir, 'package.json'), + targetPaths.resolveRoot(packageDir, 'package.json'), ); return getPackageExportDetails(pkg).map(details => { @@ -143,11 +141,7 @@ export async function runApiExtraction({ // inspected. const allDistTypesEntryPointPaths = allEntryPoints.map( ({ packageDir, distTypesPath }) => { - return cliPaths.resolveTargetRoot( - './dist-types', - packageDir, - distTypesPath, - ); + return targetPaths.resolveRoot('./dist-types', packageDir, distTypesPath); }, ); @@ -172,11 +166,8 @@ export async function runApiExtraction({ ? allowWarnings.some(aw => aw === packageDir || minimatch(packageDir, aw)) : allowWarnings; - const projectFolder = cliPaths.resolveTargetRoot(packageDir); - const packageFolder = cliPaths.resolveTargetRoot( - './dist-types', - packageDir, - ); + const projectFolder = targetPaths.resolveRoot(packageDir); + const packageFolder = targetPaths.resolveRoot('./dist-types', packageDir); const remainingReportFiles = new Set( fs.readdirSync(projectFolder).filter( diff --git a/packages/repo-tools/src/commands/api-reports/buildApiReports.test.ts b/packages/repo-tools/src/commands/api-reports/buildApiReports.test.ts index ab76aec1c1..8346296f44 100644 --- a/packages/repo-tools/src/commands/api-reports/buildApiReports.test.ts +++ b/packages/repo-tools/src/commands/api-reports/buildApiReports.test.ts @@ -16,7 +16,7 @@ import { createMockDirectory } from '@backstage/backend-test-utils'; import { normalize } from 'node:path'; -import * as pathsLib from '../../lib/paths'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { categorizePackageDirs } from './categorizePackageDirs'; @@ -51,14 +51,9 @@ jest.mock('./categorizePackageDirs', () => ({ }), })); -const projectPaths = pathsLib.paths; - const mockDir = createMockDirectory(); +overrideTargetPaths(mockDir.path); -jest.spyOn(projectPaths, 'targetRoot', 'get').mockReturnValue(mockDir.path); -jest - .spyOn(projectPaths, 'resolveTargetRoot') - .mockImplementation((...path) => mockDir.resolve(...path)); jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ { dir: normalize(mockDir.resolve('packages/package-a')), @@ -85,30 +80,28 @@ jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ describe('buildApiReports', () => { beforeEach(() => { mockDir.setContent({ - [projectPaths.targetRoot]: { - 'package.json': JSON.stringify({ - workspaces: { packages: ['packages/*', 'plugins/*'] }, - }), - packages: { - 'package-a': { - 'package.json': '{}', - }, - 'package-b': { - 'package.json': '{}', - }, - 'package-c': {}, - 'README.md': 'Hello World', + 'package.json': JSON.stringify({ + workspaces: { packages: ['packages/*', 'plugins/*'] }, + }), + packages: { + 'package-a': { + 'package.json': '{}', }, - plugins: { - 'plugin-a': { - 'package.json': '{}', - }, - 'plugin-b': { - 'package.json': '{}', - }, - 'plugin-c': { - 'package.json': '{}', - }, + 'package-b': { + 'package.json': '{}', + }, + 'package-c': {}, + 'README.md': 'Hello World', + }, + plugins: { + 'plugin-a': { + 'package.json': '{}', + }, + 'plugin-b': { + 'package.json': '{}', + }, + 'plugin-c': { + 'package.json': '{}', }, }, }); diff --git a/packages/repo-tools/src/commands/api-reports/buildApiReports.ts b/packages/repo-tools/src/commands/api-reports/buildApiReports.ts index 74b110236f..41c6aa8a57 100644 --- a/packages/repo-tools/src/commands/api-reports/buildApiReports.ts +++ b/packages/repo-tools/src/commands/api-reports/buildApiReports.ts @@ -16,7 +16,8 @@ import { OptionValues } from 'commander'; import { categorizePackageDirs } from './categorizePackageDirs'; -import { paths as cliPaths, resolvePackagePaths } from '../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; +import { resolvePackagePaths } from '../../lib/paths'; import { runSqlExtraction } from './sql-reports'; import { runCliExtraction } from './cli-reports'; import { @@ -37,9 +38,7 @@ type Options = { } & OptionValues; export async function buildApiReports(paths: string[] = [], opts: Options) { - const tmpDir = cliPaths.resolveTargetRoot( - './node_modules/.cache/api-extractor', - ); + const tmpDir = targetPaths.resolveRoot('./node_modules/.cache/api-extractor'); const isCiBuild = opts.ci; const isDocsBuild = opts.docs; @@ -73,7 +72,7 @@ export async function buildApiReports(paths: string[] = [], opts: Options) { temporaryTsConfigPath = await createTemporaryTsConfig(selectedPackageDirs); } const tsconfigFilePath = - temporaryTsConfigPath ?? cliPaths.resolveTargetRoot('tsconfig.json'); + temporaryTsConfigPath ?? targetPaths.resolveRoot('tsconfig.json'); if (runTsc) { console.log('# Compiling TypeScript'); @@ -116,7 +115,7 @@ export async function buildApiReports(paths: string[] = [], opts: Options) { console.log('# Generating package documentation'); await buildDocs({ inputDir: tmpDir, - outputDir: cliPaths.resolveTargetRoot('docs/reference'), + outputDir: targetPaths.resolveRoot('docs/reference'), }); } } diff --git a/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts b/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts index 86694c3d68..973c7b8acb 100644 --- a/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts +++ b/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts @@ -15,7 +15,7 @@ */ import fs from 'fs-extra'; -import { paths as cliPaths } from '../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; export async function categorizePackageDirs(packageDirs: string[]) { const dirs = packageDirs.slice(); @@ -34,7 +34,7 @@ export async function categorizePackageDirs(packageDirs: string[]) { } const pkgJson = await fs - .readJson(cliPaths.resolveTargetRoot(dir, 'package.json')) + .readJson(targetPaths.resolveRoot(dir, 'package.json')) .catch(error => { if (error.code === 'ENOENT') { return undefined; @@ -45,9 +45,7 @@ export async function categorizePackageDirs(packageDirs: string[]) { if (!role) { return; // Ignore packages without roles } - if ( - await fs.pathExists(cliPaths.resolveTargetRoot(dir, 'migrations')) - ) { + if (await fs.pathExists(targetPaths.resolveRoot(dir, 'migrations'))) { sqlPackageDirs.push(dir); } // TODO(Rugvip): Inlined packages are ignored because we can't handle @internal exports diff --git a/packages/repo-tools/src/commands/api-reports/cli-reports/runCliExtraction.ts b/packages/repo-tools/src/commands/api-reports/cli-reports/runCliExtraction.ts index 8aa0eea02c..146c83bcfb 100644 --- a/packages/repo-tools/src/commands/api-reports/cli-reports/runCliExtraction.ts +++ b/packages/repo-tools/src/commands/api-reports/cli-reports/runCliExtraction.ts @@ -22,7 +22,7 @@ import { import fs from 'fs-extra'; import { createBinRunner } from '../../util'; import { CliHelpPage, CliModel } from './types'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import { generateCliReport } from './generateCliReport'; import { logApiReportInstructions } from '../common'; @@ -115,7 +115,7 @@ export async function runCliExtraction({ }: CliExtractionOptions) { for (const packageDir of packageDirs) { console.log(`## Processing ${packageDir}`); - const fullDir = cliPaths.resolveTargetRoot(packageDir); + const fullDir = targetPaths.resolveRoot(packageDir); const pkgJson = await fs.readJson(resolvePath(fullDir, 'package.json')); if (!pkgJson.bin) { @@ -162,7 +162,7 @@ export async function runCliExtraction({ console.log(''); console.log( `The conflicting file is ${relativePath( - cliPaths.targetRoot, + targetPaths.rootDir, reportPath, )}, expecting the following content:`, ); diff --git a/packages/repo-tools/src/commands/api-reports/common/tryRunPrettier.ts b/packages/repo-tools/src/commands/api-reports/common/tryRunPrettier.ts index 174b68f499..2c95e71647 100644 --- a/packages/repo-tools/src/commands/api-reports/common/tryRunPrettier.ts +++ b/packages/repo-tools/src/commands/api-reports/common/tryRunPrettier.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import type { Config } from 'prettier'; /** @@ -33,7 +33,7 @@ export async function tryRunPrettierAsync( // Filepath for proper config resolution const filepath = extraConfig.filepath ?? - `${cliPaths.targetRoot}/should-not-be-ignored.any`; + `${targetPaths.rootDir}/should-not-be-ignored.any`; const config = (await prettier.resolveConfig(filepath, { editorconfig: true })) ?? {}; const formattedContent = prettier.format(content, { @@ -68,7 +68,7 @@ export function createPrettierSyncFormatter( // We need a filepath for proper config resolution, not just a directory const filepath = extraConfig.filepath ?? - `${cliPaths.targetRoot}/should-not-be-ignored.any`; + `${targetPaths.rootDir}/should-not-be-ignored.any`; const resolveConfig = // @ts-expect-error: v2 requires .sync, @prettier/sync v3 does not prettierSync.resolveConfig?.sync ?? prettierSync.resolveConfig; diff --git a/packages/repo-tools/src/commands/api-reports/sql-reports/runSqlExtraction.ts b/packages/repo-tools/src/commands/api-reports/sql-reports/runSqlExtraction.ts index 6268d0d30d..375ce07476 100644 --- a/packages/repo-tools/src/commands/api-reports/sql-reports/runSqlExtraction.ts +++ b/packages/repo-tools/src/commands/api-reports/sql-reports/runSqlExtraction.ts @@ -16,7 +16,7 @@ import fs, { readJson } from 'fs-extra'; import { relative as relativePath } from 'node:path'; -import { paths as cliPaths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import { diff as justDiff } from 'just-diff'; import { SchemaInfo } from './types'; import { getPgSchemaInfo } from './getPgSchemaInfo'; @@ -43,14 +43,14 @@ export async function runSqlExtraction(options: SqlExtractionOptions) { let dbIndex = 1; for (const packageDir of options.packageDirs) { - const migrationDir = cliPaths.resolveTargetRoot(packageDir, 'migrations'); + const migrationDir = targetPaths.resolveRoot(packageDir, 'migrations'); if (!(await fs.pathExists(migrationDir))) { console.log(`No SQL migrations found in ${packageDir}`); continue; } const { name: pkgName } = await readJson( - cliPaths.resolveTargetRoot(packageDir, 'package.json'), + targetPaths.resolveRoot(packageDir, 'package.json'), ); const migrationFiles = await fs.readdir(migrationDir, { @@ -95,7 +95,7 @@ async function runSingleSqlExtraction( knex: Knex, options: SqlExtractionOptions, ) { - const migrationDir = cliPaths.resolveTargetRoot( + const migrationDir = targetPaths.resolveRoot( targetDir, 'migrations', migrationTarget, @@ -152,7 +152,7 @@ async function runSingleSqlExtraction( break; } } - const reportPath = cliPaths.resolveTargetRoot( + const reportPath = targetPaths.resolveRoot( targetDir, `report${migrationTarget === '.' ? '' : `-${migrationTarget}`}.sql.md`, ); @@ -182,7 +182,7 @@ async function runSingleSqlExtraction( console.log(''); console.log( `The conflicting file is ${relativePath( - cliPaths.targetRoot, + targetPaths.rootDir, reportPath, )}, expecting the following content:`, ); diff --git a/packages/repo-tools/src/commands/knip-reports/knip-extractor.ts b/packages/repo-tools/src/commands/knip-reports/knip-extractor.ts index ab5af976bf..d7eadb3523 100644 --- a/packages/repo-tools/src/commands/knip-reports/knip-extractor.ts +++ b/packages/repo-tools/src/commands/knip-reports/knip-extractor.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { paths as cliPaths } from '../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import pLimit from 'p-limit'; import os from 'node:os'; import { relative as relativePath, resolve as resolvePath } from 'node:path'; @@ -100,9 +100,9 @@ async function handlePackage({ }: KnipPackageOptions) { console.log(`## Processing ${packageDir}`); - const fullDir = cliPaths.resolveTargetRoot(packageDir); + const fullDir = targetPaths.resolveRoot(packageDir); const reportPath = resolvePath(fullDir, 'knip-report.md'); - const run = createBinRunner(cliPaths.targetRoot, ''); + const run = createBinRunner(targetPaths.rootDir, ''); let report = await run( `${knipDir}/knip.js`, @@ -149,7 +149,7 @@ async function handlePackage({ console.log(''); console.log( `The conflicting file is ${relativePath( - cliPaths.targetRoot, + targetPaths.rootDir, reportPath, )}, expecting the following content:`, ); @@ -168,8 +168,8 @@ export async function runKnipReports({ packageDirs, isLocalBuild, }: KnipExtractionOptions) { - const knipDir = cliPaths.resolveTargetRoot('./node_modules/knip/bin/'); - const knipConfigPath = cliPaths.resolveTargetRoot('./knip.json'); + const knipDir = targetPaths.resolveRoot('./node_modules/knip/bin/'); + const knipConfigPath = targetPaths.resolveRoot('./knip.json'); const limiter = pLimit(os.cpus().length); await generateKnipConfig({ knipConfigPath }); diff --git a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts index 3f0424c547..9e2c664e60 100644 --- a/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts +++ b/packages/repo-tools/src/commands/lint-legacy-backend-exports/lint-legacy-backend-exports.ts @@ -16,11 +16,11 @@ import { Project } from 'ts-morph'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; import fs from 'fs-extra'; -import { paths as cliPaths } from '../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import path from 'node:path'; const project = new Project({ - tsConfigFilePath: cliPaths.resolveTargetRoot('tsconfig.json'), + tsConfigFilePath: targetPaths.resolveRoot('tsconfig.json'), }); function readPackageJson(pkg: string) { diff --git a/packages/repo-tools/src/commands/package-docs/command.ts b/packages/repo-tools/src/commands/package-docs/command.ts index 39568e1b00..3e635b34f4 100644 --- a/packages/repo-tools/src/commands/package-docs/command.ts +++ b/packages/repo-tools/src/commands/package-docs/command.ts @@ -15,7 +15,8 @@ */ import { exec } from 'node:child_process'; import { promisify } from 'node:util'; -import { paths as cliPaths, resolvePackagePaths } from '../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; +import { resolvePackagePaths } from '../../lib/paths'; import { createTemporaryTsConfig } from './utils'; import { readFile, rm, writeFile } from 'node:fs/promises'; import pLimit from 'p-limit'; @@ -74,7 +75,7 @@ async function generateDocJson(pkg: string) { const temporaryTsConfigPath: string = await createTemporaryTsConfig(pkg); const packageJson = JSON.parse( - await readFile(cliPaths.resolveTargetRoot(pkg, 'package.json'), 'utf-8'), + await readFile(targetPaths.resolveRoot(pkg, 'package.json'), 'utf-8'), ); const exports = getExports(packageJson); @@ -85,17 +86,17 @@ async function generateDocJson(pkg: string) { return false; } - await mkdirp(cliPaths.resolveTargetRoot(`dist-types`, pkg)); + await mkdirp(targetPaths.resolveRoot(`dist-types`, pkg)); const { stdout, stderr } = await execAsync( [ - cliPaths.resolveTargetRoot('node_modules/.bin/typedoc'), + targetPaths.resolveRoot('node_modules/.bin/typedoc'), '--json', - cliPaths.resolveTargetRoot(`dist-types`, pkg, 'docs.json'), + targetPaths.resolveRoot(`dist-types`, pkg, 'docs.json'), '--tsconfig', temporaryTsConfigPath, '--basePath', - cliPaths.targetRoot, + targetPaths.rootDir, '--skipErrorChecking', ...(getExports(packageJson).flatMap(e => [ '--entryPoints', @@ -117,7 +118,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { console.warn('!!! This is an experimental command !!!'); const existingDocsJsonPaths = glob.sync( - cliPaths.resolveTargetRoot('dist-types/**/docs.json'), + targetPaths.resolveRoot('dist-types/**/docs.json'), ); if (existingDocsJsonPaths.length > 0) { console.warn( @@ -129,7 +130,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { } } console.warn('!!! Deleting existing docs output !!!'); - await rm(cliPaths.resolveTargetRoot('type-docs'), { + await rm(targetPaths.resolveRoot('type-docs'), { recursive: true, force: true, }); @@ -140,8 +141,8 @@ export default async function packageDocs(paths: string[] = [], opts: any) { }); const cache = await PackageDocsCache.loadAsync( - cliPaths.resolveTargetRoot(), - await Lockfile.load(cliPaths.resolveTargetRoot('yarn.lock')), + targetPaths.rootDir, + await Lockfile.load(targetPaths.resolveRoot('yarn.lock')), ); console.log(`### Generating docs.`); @@ -149,10 +150,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { selectedPackageDirs.map(pkg => limit(async () => { const pkgJson = JSON.parse( - await readFile( - cliPaths.resolveTargetRoot(pkg, 'package.json'), - 'utf-8', - ), + await readFile(targetPaths.resolveRoot(pkg, 'package.json'), 'utf-8'), ); if (EXCLUDE.includes(pkg) || pkgJson.name.startsWith('@internal/')) { return; @@ -171,10 +169,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { console.log(`### Processing ${pkg}`); const success = await generateDocJson(pkg); if (success) { - await cache.write( - pkg, - cliPaths.resolveTargetRoot(`dist-types`, pkg), - ); + await cache.write(pkg, targetPaths.resolveRoot(`dist-types`, pkg)); } } catch (e) { console.error('Failed to generate docs for', pkg); @@ -187,7 +182,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { const generatedPackageDirs = []; for (const pkg of selectedPackageDirs) { try { - const docsJsonPath = cliPaths.resolveTargetRoot( + const docsJsonPath = targetPaths.resolveRoot( `dist-types/${pkg}/docs.json`, ); const docsJson = JSON.parse(await readFile(docsJsonPath, 'utf-8')); @@ -211,7 +206,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { const { stdout, stderr } = await execAsync( [ - cliPaths.resolveTargetRoot('node_modules/.bin/typedoc'), + targetPaths.resolveRoot('node_modules/.bin/typedoc'), '--entryPointStrategy', 'merge', ...generatedPackageDirs.flatMap(pkg => [ @@ -220,13 +215,13 @@ export default async function packageDocs(paths: string[] = [], opts: any) { ]), ...HIGHLIGHT_LANGUAGES.flatMap(e => ['--highlightLanguages', e]), '--out', - cliPaths.resolveTargetRoot('type-docs'), - ...(existsSync(cliPaths.resolveTargetRoot('typedoc.json')) - ? ['--options', cliPaths.resolveTargetRoot('typedoc.json')] + targetPaths.resolveRoot('type-docs'), + ...(existsSync(targetPaths.resolveRoot('typedoc.json')) + ? ['--options', targetPaths.resolveRoot('typedoc.json')] : []), ].join(' '), { - cwd: cliPaths.targetRoot, + cwd: targetPaths.rootDir, }, ); diff --git a/packages/repo-tools/src/commands/package-docs/utils.ts b/packages/repo-tools/src/commands/package-docs/utils.ts index 2cb95443b6..21294daa79 100644 --- a/packages/repo-tools/src/commands/package-docs/utils.ts +++ b/packages/repo-tools/src/commands/package-docs/utils.ts @@ -14,11 +14,15 @@ * limitations under the License. */ +import { findOwnPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; -import { paths as cliPaths } from '../../lib/paths'; export async function createTemporaryTsConfig(dir: string) { - const path = cliPaths.resolveOwnRoot(dir, 'tsconfig.typedoc.tmp.json'); + /* eslint-disable-next-line no-restricted-syntax */ + const path = findOwnPaths(__dirname).resolveRoot( + dir, + 'tsconfig.typedoc.tmp.json', + ); process.once('exit', () => { fs.removeSync(path); diff --git a/packages/repo-tools/src/commands/package/schema/openapi/diff.ts b/packages/repo-tools/src/commands/package/schema/openapi/diff.ts index 2f0af30881..851b2b3a48 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/diff.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/diff.ts @@ -16,7 +16,7 @@ import chalk from 'chalk'; import { exec } from '../../../../lib/exec'; import { getPathToCurrentOpenApiSpec } from '../../../../lib/openapi/helpers'; -import { paths as cliPaths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import { OptionValues } from 'commander'; import { env } from 'node:process'; import { readFile, rm } from 'node:fs/promises'; @@ -53,7 +53,7 @@ async function check(opts: OptionValues) { baseRef, ], { - cwd: cliPaths.targetRoot, + cwd: targetPaths.rootDir, env: { CI: opts.json ? '1' : undefined, ...env }, }, ); @@ -65,7 +65,7 @@ async function check(opts: OptionValues) { if (opts.json) { const file = ( - await readFile(resolve(cliPaths.targetRoot, 'ci-run-details.json')) + await readFile(resolve(targetPaths.rootDir, 'ci-run-details.json')) ).toString(); const results = JSON.parse(file); console.log(file); @@ -73,7 +73,7 @@ async function check(opts: OptionValues) { throw new Error('Some checks failed'); } - await rm(resolve(cliPaths.targetRoot, 'ci-run-details.json')); + await rm(resolve(targetPaths.rootDir, 'ci-run-details.json')); } else { console.log(reduceOpticOutput(output)); if (!opts.ignore && failed) { diff --git a/packages/repo-tools/src/commands/package/schema/openapi/fuzz.ts b/packages/repo-tools/src/commands/package/schema/openapi/fuzz.ts index 29b038ac5a..12e5d7d527 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/fuzz.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/fuzz.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import fs from 'fs-extra'; -import { paths as cliPaths } from '../../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import chalk from 'chalk'; import { spawn } from '../../../../lib/exec'; import { getPathToCurrentOpenApiSpec } from '../../../../lib/openapi/helpers'; @@ -40,7 +40,7 @@ async function fuzz(opts: OptionValues) { await fs.readFile(resolvedOpenapiPath, 'utf8'), ) as { info: { title: string } }; const configSource = ConfigSources.default({ - rootDir: cliPaths.targetRoot, + rootDir: targetPaths.rootDir, }); const config = await ConfigSources.toConfig(configSource); const pluginId = openapiSpec.info.title; @@ -48,7 +48,7 @@ async function fuzz(opts: OptionValues) { if (opts.debug) { args.push( '--cassette-path', - cliPaths.resolveTargetRoot(join('.cassettes', `${pluginId}.yml`)), + targetPaths.resolveRoot(join('.cassettes', `${pluginId}.yml`)), ); } diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts index 24f8496a0d..c5b2807fbd 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts @@ -24,11 +24,11 @@ import { OUTPUT_PATH, } from '../../../../../lib/openapi/constants'; import { deduplicateImports } from '../../../../../lib/openapi/dedupe-imports'; +import { targetPaths } from '@backstage/cli-common'; import { getPathToCurrentOpenApiSpec, toGeneratorAdditionalProperties, } from '../../../../../lib/openapi/helpers'; -import { paths as cliPaths } from '../../../../../lib/paths'; async function generate( outputDirectory: string, @@ -36,7 +36,7 @@ async function generate( abortSignal?: AbortController, ) { const resolvedOpenapiPath = await getPathToCurrentOpenApiSpec(); - const resolvedOutputDirectory = cliPaths.resolveTargetRoot( + const resolvedOutputDirectory = targetPaths.resolveRoot( outputDirectory, OUTPUT_PATH, ); @@ -87,7 +87,7 @@ async function generate( await fs.writeFile( resolve(parentDirectory, 'index.ts'), - `// + `// export * from './generated';`, ); @@ -95,8 +95,8 @@ async function generate( signal: abortSignal?.signal, }); - const prettier = cliPaths.resolveTargetRoot('node_modules/.bin/prettier'); - if (prettier) { + const prettier = targetPaths.resolveRoot('node_modules/.bin/prettier'); + if (await fs.pathExists(prettier)) { await exec(`${prettier} --write ${parentDirectory}`, [], { signal: abortSignal?.signal, }); diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts index be70ee68c4..e913fd3a8c 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts @@ -27,23 +27,23 @@ import { TS_SCHEMA_PATH, } from '../../../../../lib/openapi/constants'; import { deduplicateImports } from '../../../../../lib/openapi/dedupe-imports'; +import { targetPaths } from '@backstage/cli-common'; import { getPathToCurrentOpenApiSpec, getRelativePathToFile, toGeneratorAdditionalProperties, } from '../../../../../lib/openapi/helpers'; -import { paths as cliPaths } from '../../../../../lib/paths'; async function generateSpecFile() { const openapiPath = await getPathToCurrentOpenApiSpec(); const yaml = YAML.load(await fs.readFile(openapiPath, 'utf8')); - const tsPath = cliPaths.resolveTarget(TS_SCHEMA_PATH); + const tsPath = targetPaths.resolve(TS_SCHEMA_PATH); const schemaDir = dirname(tsPath); await fs.mkdirp(schemaDir); - const oldTsPath = cliPaths.resolveTarget(OLD_SCHEMA_PATH); + const oldTsPath = targetPaths.resolve(OLD_SCHEMA_PATH); if (fs.existsSync(oldTsPath)) { console.warn(`Removing old schema file at ${oldTsPath}`); fs.removeSync(oldTsPath); @@ -77,9 +77,11 @@ export const createOpenApiRouter = async ( ); await exec(`yarn backstage-cli package lint`, ['--fix', tsPath, indexFile]); - if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { + if ( + await fs.pathExists(targetPaths.resolveRoot('node_modules/.bin/prettier')) + ) { await exec(`yarn prettier`, ['--write', tsPath, indexFile], { - cwd: cliPaths.targetRoot, + cwd: targetPaths.rootDir, }); } } @@ -150,7 +152,7 @@ async function generate( }, ); - const prettier = cliPaths.resolveTargetRoot('node_modules/.bin/prettier'); + const prettier = targetPaths.resolveRoot('node_modules/.bin/prettier'); if (prettier) { await exec(`${prettier} --write ${resolvedOutputDirectory}`, [], { signal: abortSignal?.signal, diff --git a/packages/repo-tools/src/commands/package/schema/openapi/init.ts b/packages/repo-tools/src/commands/package/schema/openapi/init.ts index 00e82f65df..04b6e73483 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/init.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/init.ts @@ -14,8 +14,8 @@ * limitations under the License. */ import fs from 'fs-extra'; +import { targetPaths } from '@backstage/cli-common'; import { YAML_SCHEMA_PATH } from '../../../../lib/openapi/constants'; -import { paths as cliPaths } from '../../../../lib/paths'; import chalk from 'chalk'; import { exec } from '../../../../lib/exec'; import { @@ -49,7 +49,7 @@ capture: ${YAML_SCHEMA_PATH}: # 🔧 Runnable example with simple get requests. # Run with "PORT=3000 optic capture ${YAML_SCHEMA_PATH} --update interactive" in '${ - cliPaths.targetDir + targetPaths.dir }' # You can change the server and the 'requests' section to experiment server: @@ -61,10 +61,12 @@ capture: # 🔧 Specify a command that will generate traffic command: yarn backstage-cli package test --no-watch ${ROUTER_TEST_PATHS.map( e => `"${e}"`, - ).join(' ')} + ).join(' ')} `, ); - if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { + if ( + await fs.pathExists(targetPaths.resolveRoot('node_modules/.bin/prettier')) + ) { await exec(`yarn prettier`, ['--write', opticConfigFilePath]); } } diff --git a/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts b/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts index 02f3db0c43..2648f78f06 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/diff.ts @@ -16,16 +16,16 @@ import { PackageGraph } from '@backstage/cli-node'; import { OptionValues } from 'commander'; import { exec } from '../../../../lib/exec'; +import { targetPaths } from '@backstage/cli-common'; import { CiRunDetails, generateCompareSummaryMarkdown, } from '../../../../lib/openapi/optic/helpers'; -import { paths as cliPaths } from '../../../../lib/paths'; import { YAML_SCHEMA_PATH } from '../../../../lib/openapi/constants'; function cleanUpApiName(e: { apiName: string }) { e.apiName = e.apiName - .replace(cliPaths.targetDir, '') + .replace(targetPaths.dir, '') .replace(YAML_SCHEMA_PATH, ''); } @@ -46,7 +46,7 @@ export async function command(opts: OptionValues) { const changedOpenApiSpecs = changedFiles .split('\n') .filter(e => e.endsWith(YAML_SCHEMA_PATH)) - .map(e => cliPaths.resolveTarget(e)); + .map(e => targetPaths.resolve(e)); // filter packages by changedFiles packages = packages.filter(pkg => diff --git a/packages/repo-tools/src/commands/repo/schema/openapi/test.ts b/packages/repo-tools/src/commands/repo/schema/openapi/test.ts index 233c50a1fa..e735e729c6 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/test.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/test.ts @@ -17,9 +17,9 @@ import fs from 'fs-extra'; import { join } from 'node:path'; import chalk from 'chalk'; +import { findOwnPaths, targetPaths } from '@backstage/cli-common'; import { runner } from '../../../../lib/runner'; import { YAML_SCHEMA_PATH } from '../../../../lib/openapi/constants'; -import { paths as cliPaths } from '../../../../lib/paths'; import { exec } from '../../../../lib/exec'; import { getPathToOpenApiSpec } from '../../../../lib/openapi/helpers'; @@ -42,7 +42,10 @@ async function test( let opticLocation = ''; try { opticLocation = ( - await exec(`yarn bin optic`, [], { cwd: cliPaths.ownRoot }) + await exec(`yarn bin optic`, [], { + /* eslint-disable-next-line no-restricted-syntax */ + cwd: findOwnPaths(__dirname).rootDir, + }) ).stdout as string; } catch (err) { throw new Error( @@ -79,7 +82,9 @@ async function test( throw err; } if ( - (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) && + (await fs.pathExists( + targetPaths.resolveRoot('node_modules/.bin/prettier'), + )) && options?.update ) { await exec(`yarn prettier`, ['--write', openapiPath]); diff --git a/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts b/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts index 2aa0392fae..9834009d09 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/verify.ts @@ -19,8 +19,8 @@ import { isEqual } from 'lodash'; import { join } from 'node:path'; import chalk from 'chalk'; import { relative as relativePath, resolve as resolvePath } from 'node:path'; +import { targetPaths } from '@backstage/cli-common'; import { runner } from '../../../../lib/runner'; -import { paths as cliPaths } from '../../../../lib/paths'; import { OLD_SCHEMA_PATH, TS_SCHEMA_PATH, @@ -60,7 +60,7 @@ async function verify(directoryPath: string) { throw new Error(`\`${TS_SCHEMA_PATH}\` needs to have a 'spec' export.`); } if (!isEqual(schema.spec, yaml)) { - const path = relativePath(cliPaths.targetRoot, directoryPath); + const path = relativePath(targetPaths.rootDir, directoryPath); throw new Error( `\`${YAML_SCHEMA_PATH}\` and \`${TS_SCHEMA_PATH}\` do not match. Please run \`yarn backstage-repo-tools package schema openapi generate\` from '${path}' to regenerate \`${TS_SCHEMA_PATH}\`.`, ); diff --git a/packages/repo-tools/src/lib/openapi/helpers.ts b/packages/repo-tools/src/lib/openapi/helpers.ts index 5d1bcf58c7..d6b6927660 100644 --- a/packages/repo-tools/src/lib/openapi/helpers.ts +++ b/packages/repo-tools/src/lib/openapi/helpers.ts @@ -18,8 +18,8 @@ import Parser from '@apidevtools/swagger-parser'; import fs, { pathExists } from 'fs-extra'; import YAML from 'js-yaml'; import { cloneDeep } from 'lodash'; +import { targetPaths } from '@backstage/cli-common'; import { resolve } from 'node:path'; -import { paths } from '../paths'; import { YAML_SCHEMA_PATH } from './constants'; export const getPathToFile = async (directory: string, filename: string) => { @@ -27,7 +27,7 @@ export const getPathToFile = async (directory: string, filename: string) => { }; export const getRelativePathToFile = async (filename: string) => { - return await getPathToFile(paths.targetDir, filename); + return await getPathToFile(targetPaths.dir, filename); }; export const assertExists = async (path: string) => { diff --git a/packages/repo-tools/src/lib/paths.ts b/packages/repo-tools/src/lib/paths.ts index ccca6f09c9..fea456ea3e 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -14,14 +14,11 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; import { PackageGraph } from '@backstage/cli-node'; import { Minimatch } from 'minimatch'; import { isAbsolute, relative as relativePath } from 'node:path'; -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); - /** @internal */ export interface ResolvePackagesOptions { paths?: string[]; @@ -41,7 +38,7 @@ export async function resolvePackagePaths( for (const path of providedPaths) { const matches = packages.some( ({ dir }) => - new Minimatch(path).match(relativePath(paths.targetRoot, dir)) || + new Minimatch(path).match(relativePath(targetPaths.rootDir, dir)) || isChildPath(dir, path), ); if (!matches) { @@ -57,7 +54,7 @@ export async function resolvePackagePaths( packages = packages.filter(({ dir }) => providedPaths.some( path => - new Minimatch(path).match(relativePath(paths.targetRoot, dir)) || + new Minimatch(path).match(relativePath(targetPaths.rootDir, dir)) || isChildPath(dir, path), ), ); @@ -66,7 +63,9 @@ export async function resolvePackagePaths( if (include) { packages = packages.filter(pkg => include.some(pattern => - new Minimatch(pattern).match(relativePath(paths.targetRoot, pkg.dir)), + new Minimatch(pattern).match( + relativePath(targetPaths.rootDir, pkg.dir), + ), ), ); } @@ -76,13 +75,13 @@ export async function resolvePackagePaths( exclude.some( pattern => !new Minimatch(pattern).match( - relativePath(paths.targetRoot, pkg.dir), + relativePath(targetPaths.rootDir, pkg.dir), ), ), ); } - return packages.map(pkg => relativePath(paths.targetRoot, pkg.dir)); + return packages.map(pkg => relativePath(targetPaths.rootDir, pkg.dir)); } /** @internal */ diff --git a/packages/repo-tools/src/lib/runner.ts b/packages/repo-tools/src/lib/runner.ts index 7061a195ad..193a267cf0 100644 --- a/packages/repo-tools/src/lib/runner.ts +++ b/packages/repo-tools/src/lib/runner.ts @@ -14,10 +14,10 @@ * limitations under the License. */ +import { targetPaths } from '@backstage/cli-common'; import { resolvePackagePaths } from './paths'; import pLimit from 'p-limit'; import { relative as relativePath } from 'node:path'; -import { paths as cliPaths } from './paths'; import portFinder from 'portfinder'; export async function runner( @@ -58,7 +58,7 @@ export async function runner( } return { - relativeDir: relativePath(cliPaths.targetRoot, pkg), + relativeDir: relativePath(targetPaths.rootDir, pkg), resultText, }; }), diff --git a/packages/scaffolder-internal/CHANGELOG.md b/packages/scaffolder-internal/CHANGELOG.md index 3ae462b888..13e8c5694c 100644 --- a/packages/scaffolder-internal/CHANGELOG.md +++ b/packages/scaffolder-internal/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/scaffolder +## 0.0.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + ## 0.0.18 ### Patch Changes diff --git a/packages/scaffolder-internal/package.json b/packages/scaffolder-internal/package.json index d249b46969..32d77a2b31 100644 --- a/packages/scaffolder-internal/package.json +++ b/packages/scaffolder-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/scaffolder", - "version": "0.0.18", + "version": "0.0.19-next.0", "backstage": { "role": "web-library", "inline": true diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 5dab0b834b..2557e1f13b 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,26 @@ # techdocs-cli-embedded-app +## 0.2.118-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/cli@0.35.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/frontend-defaults@0.4.1-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 0.2.117 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 027ab9f5a0..b903033a0d 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.117", + "version": "0.2.118-next.0", "backstage": { "role": "frontend" }, diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 6c96f392ba..ce38cf8516 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,18 @@ # @techdocs/cli +## 1.10.6-next.0 + +### Patch Changes + +- 70fc178: Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. +- de62a9d: Upgraded `commander` dependency from `^12.0.0` to `^14.0.3` across all CLI packages. +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + ## 1.10.5 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 8299e76a2f..bccab2c228 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,6 +1,6 @@ { "name": "@techdocs/cli", - "version": "1.10.5", + "version": "1.10.6-next.0", "description": "Utility CLI for managing TechDocs sites in Backstage.", "backstage": { "role": "cli" diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 864861828b..10b7e1498f 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -17,7 +17,7 @@ import { OptionValues } from 'commander'; import path from 'node:path'; import openBrowser from 'react-dev-utils/openBrowser'; -import { findPaths, RunOnOutput } from '@backstage/cli-common'; +import { findOwnPaths, RunOnOutput } from '@backstage/cli-common'; import HTTPServer from '../../lib/httpServer'; import { runMkdocsServer } from '../../lib/mkdocsServer'; import { createLogger } from '../../lib/utility'; @@ -39,8 +39,8 @@ function findPreviewBundlePath(): string { // This can be tested by running `yarn pack` and extracting the resulting tarball into a directory. // Within the extracted directory, run `npm install --only=prod`. // Once that's done you can test the CLI in any directory using `node /package `. - // eslint-disable-next-line no-restricted-syntax - return findPaths(__dirname).resolveOwn('dist/embedded-app'); + /* eslint-disable-next-line no-restricted-syntax */ + return findOwnPaths(__dirname).resolve('dist/embedded-app'); } } diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 6d01201f32..86a6b08bb6 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.7.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 1.7.15 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 138b27126c..c5b4f771d2 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.7.15", + "version": "1.7.16-next.0", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/packages/theme/report.api.md b/packages/theme/report.api.md index f4e31db8e9..064f6f3e6c 100644 --- a/packages/theme/report.api.md +++ b/packages/theme/report.api.md @@ -185,7 +185,7 @@ export function createBaseThemeOptions( palette: PaletteOptions; typography: BackstageTypography; page: PageTheme; - getPageTheme: ({ themeId }: PageThemeSelector) => PageTheme; + getPageTheme: (input: PageThemeSelector) => PageTheme; }; // @public @deprecated diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md index 5911274c45..d5c6a13f66 100644 --- a/packages/ui/CHANGELOG.md +++ b/packages/ui/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/ui +## 0.12.1-next.0 + +### Patch Changes + +- a1f4bee: Made Accordion a `bg` provider so nested components like Button auto-increment their background level. Updated `useDefinition` to resolve `bg` `propDef` defaults for provider components. +- 8909359: Fixed focus-visible outline styles for Menu and Select components. + + **Affected components:** Menu, Select + +- 0f462f8: Improved type safety in `useDefinition` by centralizing prop resolution and strengthening the `BgPropsConstraint` to require that `bg` provider components declare `children` as a required prop in their OwnProps type. +- 8909359: Added proper cursor styles for RadioGroup items. + + **Affected components:** RadioGroup + +- Updated dependencies + - @backstage/version-bridge@1.0.12 + ## 0.12.0 ### Minor Changes diff --git a/packages/ui/package.json b/packages/ui/package.json index 39e99b4be7..e43f31c6c4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/ui", - "version": "0.12.0", + "version": "0.12.1-next.0", "backstage": { "role": "web-library" }, diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index 14283ed1b4..5922155e93 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -118,7 +118,7 @@ export interface AccordionGroupProps // @public export type AccordionOwnProps = { bg?: ProviderBg; - children?: ReactNode; + children: ReactNode; className?: string; }; @@ -281,7 +281,7 @@ export interface BgContextValue { } // @public -export const BgProvider: ({ bg, children }: BgProviderProps) => JSX_2.Element; +export const BgProvider: (input: BgProviderProps) => JSX_2.Element; // @public (undocumented) export interface BgProviderProps { @@ -360,7 +360,7 @@ export const BoxDefinition: { export type BoxOwnProps = { as?: keyof JSX.IntrinsicElements; bg?: Responsive; - children?: ReactNode; + children: ReactNode; className?: string; style?: CSSProperties; }; @@ -370,7 +370,7 @@ export interface BoxProps extends SpaceProps, BoxOwnProps, BoxUtilityProps, - React.HTMLAttributes {} + Omit, 'children'> {} // @public (undocumented) export type BoxUtilityProps = { @@ -1837,20 +1837,7 @@ export interface SwitchProps extends SwitchProps_2 { export const Tab: (props: TabProps) => JSX_2.Element; // @public (undocumented) -export function Table({ - columnConfig, - data, - loading, - isStale, - error, - pagination, - sort, - rowConfig, - selection, - emptyState, - className, - style, -}: TableProps): JSX_2.Element; +export function Table(input: TableProps): JSX_2.Element; // @public (undocumented) export const TableBody: ( @@ -1897,19 +1884,7 @@ export interface TableItem { } // @public -export function TablePagination({ - pageSize, - pageSizeOptions, - offset, - totalCount, - hasNextPage, - hasPreviousPage, - onNextPage, - onPreviousPage, - onPageSizeChange, - showPageSizeOptions, - getLabel, -}: TablePaginationProps): JSX_2.Element; +export function TablePagination(input: TablePaginationProps): JSX_2.Element; // @public export const TablePaginationDefinition: { diff --git a/packages/ui/src/components/Accordion/types.ts b/packages/ui/src/components/Accordion/types.ts index 8895b79086..39ce1ab5be 100644 --- a/packages/ui/src/components/Accordion/types.ts +++ b/packages/ui/src/components/Accordion/types.ts @@ -29,7 +29,7 @@ import type { ProviderBg } from '../../types'; */ export type AccordionOwnProps = { bg?: ProviderBg; - children?: ReactNode; + children: ReactNode; className?: string; }; diff --git a/packages/ui/src/components/Box/Box.stories.tsx b/packages/ui/src/components/Box/Box.stories.tsx index f5bc8e5b23..5d60d99872 100644 --- a/packages/ui/src/components/Box/Box.stories.tsx +++ b/packages/ui/src/components/Box/Box.stories.tsx @@ -60,6 +60,7 @@ export const Default = meta.story({ fontWeight: 'bold', color: '#2563eb', }, + children: null, }, }); @@ -326,6 +327,7 @@ const CardDisplay = ({ children }: { children?: ReactNode }) => { }; export const Display = meta.story({ + args: { children: null }, render: args => ( @@ -347,7 +349,7 @@ export const Display = meta.story({ }); export const BackgroundColors = meta.story({ - args: { px: '6', py: '4' }, + args: { px: '6', py: '4', children: null }, render: args => ( Default @@ -377,7 +379,7 @@ export const BackgroundColors = meta.story({ }); export const NestedNeutralColors = meta.story({ - args: { px: '6', py: '4' }, + args: { px: '6', py: '4', children: null }, render: args => ( diff --git a/packages/ui/src/components/Box/types.ts b/packages/ui/src/components/Box/types.ts index f7641d2f27..1b4259099b 100644 --- a/packages/ui/src/components/Box/types.ts +++ b/packages/ui/src/components/Box/types.ts @@ -21,7 +21,7 @@ import type { Responsive, ProviderBg, SpaceProps } from '../../types'; export type BoxOwnProps = { as?: keyof JSX.IntrinsicElements; bg?: Responsive; - children?: ReactNode; + children: ReactNode; className?: string; style?: CSSProperties; }; @@ -45,4 +45,4 @@ export interface BoxProps extends SpaceProps, BoxOwnProps, BoxUtilityProps, - React.HTMLAttributes {} + Omit, 'children'> {} diff --git a/packages/ui/src/components/Container/Container.stories.tsx b/packages/ui/src/components/Container/Container.stories.tsx index 44ff6f2d17..e6fbee091b 100644 --- a/packages/ui/src/components/Container/Container.stories.tsx +++ b/packages/ui/src/components/Container/Container.stories.tsx @@ -43,6 +43,7 @@ const DecorativeBox = () => ( backgroundImage: 'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")', }} + children={null} /> ); diff --git a/packages/ui/src/components/Flex/Flex.stories.tsx b/packages/ui/src/components/Flex/Flex.stories.tsx index 8b3b7af220..ff2aa442ea 100644 --- a/packages/ui/src/components/Flex/Flex.stories.tsx +++ b/packages/ui/src/components/Flex/Flex.stories.tsx @@ -70,6 +70,7 @@ const DecorativeBox = ({ fontWeight: 'bold', color: '#2563eb', }} + children={null} /> ); }; diff --git a/packages/ui/src/components/Grid/Grid.stories.tsx b/packages/ui/src/components/Grid/Grid.stories.tsx index d5b83d257d..b3b6957359 100644 --- a/packages/ui/src/components/Grid/Grid.stories.tsx +++ b/packages/ui/src/components/Grid/Grid.stories.tsx @@ -36,6 +36,7 @@ const FakeBox = () => ( backgroundImage: 'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")', }} + children={null} /> ); @@ -94,6 +95,7 @@ export const RowAndColumns = meta.story({ backgroundImage: 'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")', }} + children={null} /> diff --git a/packages/ui/src/components/Menu/Menu.module.css b/packages/ui/src/components/Menu/Menu.module.css index 4967d26551..6dca183395 100644 --- a/packages/ui/src/components/Menu/Menu.module.css +++ b/packages/ui/src/components/Menu/Menu.module.css @@ -69,6 +69,15 @@ padding-inline: var(--bui-space-1); display: block; + &:focus-visible { + outline: none; + } + + &[data-focus-visible] { + outline: 2px solid var(--bui-ring); + outline-offset: -2px; + } + &[data-focused] .bui-MenuItemWrapper { background: var(--bui-bg-neutral-2); color: var(--bui-fg-primary); diff --git a/packages/ui/src/components/RadioGroup/RadioGroup.module.css b/packages/ui/src/components/RadioGroup/RadioGroup.module.css index 1a2cd221ca..f6b7de0795 100644 --- a/packages/ui/src/components/RadioGroup/RadioGroup.module.css +++ b/packages/ui/src/components/RadioGroup/RadioGroup.module.css @@ -43,6 +43,7 @@ font-size: var(--bui-font-size-2); color: var(--bui-fg-primary); forced-color-adjust: none; + cursor: pointer; &:before { content: ''; @@ -103,5 +104,9 @@ background: var(--bui-bg-disabled); } } + + &[data-readonly] { + cursor: not-allowed; + } } } diff --git a/packages/ui/src/components/Select/Select.module.css b/packages/ui/src/components/Select/Select.module.css index 19118acf3c..3a5d066d1d 100644 --- a/packages/ui/src/components/Select/Select.module.css +++ b/packages/ui/src/components/Select/Select.module.css @@ -143,6 +143,11 @@ gap: var(--bui-space-2); outline: none; + &[data-focus-visible] { + outline: 2px solid var(--bui-ring); + outline-offset: 2px; + } + &[data-focused]::before { content: ''; position: absolute; diff --git a/packages/ui/src/hooks/useDefinition/helpers.ts b/packages/ui/src/hooks/useDefinition/helpers.ts index 3baf07b5af..8a990b4b6a 100644 --- a/packages/ui/src/hooks/useDefinition/helpers.ts +++ b/packages/ui/src/hooks/useDefinition/helpers.ts @@ -16,7 +16,7 @@ import { breakpoints } from '../useBreakpoint'; import { utilityClassMap } from '../../utils/utilityClassMap'; -import type { UnwrapResponsive, UtilityStyle } from './types'; +import type { ComponentConfig, UnwrapResponsive, UtilityStyle } from './types'; const namedBreakpoints = breakpoints.filter(b => b.id !== 'initial'); @@ -57,6 +57,42 @@ export function resolveResponsiveValue( return value as UnwrapResponsive; } +export function resolveDefinitionProps>( + definition: D, + props: Record, + breakpoint: string, +): { + ownPropsResolved: Record; + restProps: Record; +} { + const ownPropKeys = new Set(Object.keys(definition.propDefs)); + const utilityPropKeys = new Set(definition.utilityProps ?? []); + + const ownPropsRaw: Record = {}; + const restProps: Record = {}; + + for (const [key, value] of Object.entries(props)) { + if (ownPropKeys.has(key)) { + ownPropsRaw[key] = value; + } else if (!(utilityPropKeys as Set).has(key)) { + restProps[key] = value; + } + } + + const ownPropsResolved: Record = {}; + + for (const [key, config] of Object.entries(definition.propDefs)) { + const rawValue = ownPropsRaw[key]; + const resolvedValue = resolveResponsiveValue(rawValue, breakpoint); + const finalValue = resolvedValue ?? (config as any).default; + if (finalValue !== undefined) { + ownPropsResolved[key] = finalValue; + } + } + + return { ownPropsResolved, restProps }; +} + export function processUtilityProps( props: Record, utilityPropKeys: readonly Keys[], diff --git a/packages/ui/src/hooks/useDefinition/types.ts b/packages/ui/src/hooks/useDefinition/types.ts index 45ce5e3dc8..2ddc0c88c5 100644 --- a/packages/ui/src/hooks/useDefinition/types.ts +++ b/packages/ui/src/hooks/useDefinition/types.ts @@ -47,14 +47,22 @@ export interface ComponentConfig< /** * Type constraint that validates bg props are present in the props type. - * - Provider components must include 'bg' in their props + * - Provider components must include 'bg' in their props and 'children' in propDefs * - Consumer components don't need a bg prop */ export type BgPropsConstraint = Bg extends 'provider' ? 'bg' extends keyof P - ? {} + ? 'children' extends keyof P + ? {} extends Pick + ? { + __error: 'Bg provider components cannot have children as optional.'; + } + : {} + : { + __error: 'Bg provider components must include children in own props type.'; + } : { - __error: 'Bg provider components must include bg in props type.'; + __error: 'Bg provider components must include bg in own props type.'; } : {}; diff --git a/packages/ui/src/hooks/useDefinition/useDefinition.tsx b/packages/ui/src/hooks/useDefinition/useDefinition.tsx index 1ccf5ee5a4..6bbd08e340 100644 --- a/packages/ui/src/hooks/useDefinition/useDefinition.tsx +++ b/packages/ui/src/hooks/useDefinition/useDefinition.tsx @@ -18,7 +18,7 @@ import { ReactNode } from 'react'; import clsx from 'clsx'; import { useBreakpoint } from '../useBreakpoint'; import { useBgProvider, useBgConsumer, BgProvider } from '../useBg'; -import { resolveResponsiveValue, processUtilityProps } from './helpers'; +import { resolveDefinitionProps, processUtilityProps } from './helpers'; import type { ComponentConfig, UseDefinitionOptions, @@ -36,41 +36,19 @@ export function useDefinition< ): UseDefinitionResult { const { breakpoint } = useBreakpoint(); - // Provider: resolve bg and provide context for children - const providerBg = useBgProvider( - definition.bg === 'provider' - ? props.bg ?? (definition.propDefs as any).bg?.default - : undefined, + // Resolve all props centrally — applies responsive values and defaults + const { ownPropsResolved, restProps } = resolveDefinitionProps( + definition, + props, + breakpoint, ); - // Consumer: read parent context bg - const consumerBg = useBgConsumer(); - - const ownPropKeys = new Set(Object.keys(definition.propDefs)); - const utilityPropKeys = new Set(definition.utilityProps ?? []); - - const ownPropsRaw: Record = {}; - const restProps: Record = {}; - - for (const [key, value] of Object.entries(props)) { - if (ownPropKeys.has(key)) { - ownPropsRaw[key] = value; - } else if (!(utilityPropKeys as Set).has(key)) { - restProps[key] = value; - } - } - - const ownPropsResolved: Record = {}; const dataAttributes: Record = {}; for (const [key, config] of Object.entries(definition.propDefs)) { - const rawValue = ownPropsRaw[key]; - const resolvedValue = resolveResponsiveValue(rawValue, breakpoint); - const finalValue = resolvedValue ?? (config as any).default; + const finalValue = ownPropsResolved[key]; if (finalValue !== undefined) { - ownPropsResolved[key] = finalValue; - // Skip data-bg for bg prop when the provider path handles it if (key === 'bg' && definition.bg === 'provider') continue; @@ -81,6 +59,14 @@ export function useDefinition< } } + // Provider: resolve bg and provide context for children + const providerBg = useBgProvider( + definition.bg === 'provider' ? ownPropsResolved.bg : undefined, + ); + + // Consumer: read parent context bg + const consumerBg = useBgConsumer(); + // Provider: set data-bg from the resolved provider bg if (definition.bg === 'provider' && providerBg.bg !== undefined) { dataAttributes['data-bg'] = String(providerBg.bg); diff --git a/packages/yarn-plugin/CHANGELOG.md b/packages/yarn-plugin/CHANGELOG.md index f110bdf7d0..e5ee13b8f0 100644 --- a/packages/yarn-plugin/CHANGELOG.md +++ b/packages/yarn-plugin/CHANGELOG.md @@ -1,5 +1,14 @@ # yarn-plugin-backstage +## 0.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/errors@1.2.7 + - @backstage/release-manifests@0.0.13 + ## 0.0.9 ### Patch Changes diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index 1508d76d47..0326e3d4e9 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -1,6 +1,6 @@ { "name": "yarn-plugin-backstage", - "version": "0.0.9", + "version": "0.0.10-next.0", "description": "Yarn plugin for working with Backstage monorepos", "backstage": { "role": "node-library" diff --git a/packages/yarn-plugin/src/index.test.ts b/packages/yarn-plugin/src/index.test.ts index 688098a626..4acd6a446f 100644 --- a/packages/yarn-plugin/src/index.test.ts +++ b/packages/yarn-plugin/src/index.test.ts @@ -19,7 +19,7 @@ import { spawn, SpawnOptionsWithoutStdio } from 'node:child_process'; import fs from 'fs-extra'; import yaml from 'yaml'; import { buildDepTreeFromFiles } from 'snyk-nodejs-lockfile-parser'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; import { createMockDirectory } from '@backstage/backend-test-utils'; jest.setTimeout(30_000); @@ -86,7 +86,7 @@ describe('Backstage yarn plugin', () => { let initialLockFileContent: string | undefined; beforeAll(async () => { - const { targetRoot } = findPaths(process.cwd()); + const targetRoot = targetPaths.rootDir; await executeCommand('yarn', ['build'], { cwd: joinPath(targetRoot, 'packages/yarn-plugin'), }); diff --git a/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts b/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts index 11538b3d50..083baae907 100644 --- a/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts +++ b/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { findPaths, Paths } from '@backstage/cli-common'; - const setPlatform = (platform: string) => { Object.defineProperty(process, `platform`, { configurable: true, @@ -37,7 +35,6 @@ describe('getWorkspaceRoot', () => { `('platform: $platform', ({ platform, native, portable }) => { let realPlatform: string; let getWorkspaceRoot: () => string; - let mockFindPaths: jest.MockedFunction; beforeEach(() => { realPlatform = process.platform; @@ -45,13 +42,10 @@ describe('getWorkspaceRoot', () => { jest.resetModules(); - mockFindPaths = jest.fn(); - - jest.doMock('@backstage/cli-common', () => ({ - ...jest.requireActual('@backstage/cli-common'), - findPaths: mockFindPaths, - })); - + const { + overrideTargetPaths, + } = require('@backstage/cli-common/testUtils'); + overrideTargetPaths(native); getWorkspaceRoot = require('./getWorkspaceRoot').getWorkspaceRoot; }); @@ -60,10 +54,6 @@ describe('getWorkspaceRoot', () => { }); it('returns an appropriately-formatted workspace root path', () => { - mockFindPaths.mockReturnValue({ - targetRoot: native, - } as Paths); - expect(getWorkspaceRoot()).toEqual(portable); }); }); diff --git a/packages/yarn-plugin/src/util/getWorkspaceRoot.ts b/packages/yarn-plugin/src/util/getWorkspaceRoot.ts index d6f3e98e10..57e03daabe 100644 --- a/packages/yarn-plugin/src/util/getWorkspaceRoot.ts +++ b/packages/yarn-plugin/src/util/getWorkspaceRoot.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import { npath, ppath } from '@yarnpkg/fslib'; -import { findPaths } from '@backstage/cli-common'; +import { npath } from '@yarnpkg/fslib'; +import { targetPaths } from '@backstage/cli-common'; export const getWorkspaceRoot = () => { - return npath.toPortablePath( - findPaths(npath.fromPortablePath(ppath.cwd())).targetRoot, - ); + return npath.toPortablePath(targetPaths.rootDir); }; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index db43c0c9dd..9db7a5ed41 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-api-docs +## 0.13.5-next.0 + +### Patch Changes + +- 9c9d425: Fixed invisible text in parameter input fields when using dark mode in OpenAPI definition pages +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.13.4 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 72562c51bd..c3f5a2c42b 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.13.4", + "version": "0.13.5-next.0", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 1750238b78..ea52804fdf 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-app-backend +## 0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-app-node@0.1.43-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.5.11 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index d38826ddc4..298208ac61 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.5.11", + "version": "0.5.12-next.0", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index c21429e06a..9d5856ac62 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-node +## 0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + ## 0.1.42 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 3ef2f0a682..2454c3563a 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-node", - "version": "0.1.42", + "version": "0.1.43-next.0", "description": "Node.js library for the app plugin", "backstage": { "role": "node-library", diff --git a/plugins/app-react/CHANGELOG.md b/plugins/app-react/CHANGELOG.md index 75e91969e7..6374706f5c 100644 --- a/plugins/app-react/CHANGELOG.md +++ b/plugins/app-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-app-react +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/app-react/package.json b/plugins/app-react/package.json index 3dc8213bc8..9c6887c1ba 100644 --- a/plugins/app-react/package.json +++ b/plugins/app-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-react", - "version": "0.2.0", + "version": "0.2.1-next.0", "description": "Web library for the app plugin", "backstage": { "role": "web-library", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md index 3cd61a7955..f61e2935b9 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-app-visualizer +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 173c1cb9f1..5353caa37e 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-visualizer", - "version": "0.2.0", + "version": "0.2.1-next.0", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index a13ad26fff..e4cd22f5b4 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-app +## 0.4.1-next.0 + +### Patch Changes + +- 909c742: Switched translation API imports (`translationApiRef`, `appLanguageApiRef`) from the alpha `@backstage/core-plugin-api/alpha` path to the stable `@backstage/frontend-plugin-api` export. This has no effect on runtime behavior. +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-app-react@0.2.1-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/app/package.json b/plugins/app/package.json index 780996e3b0..3572d7da28 100644 --- a/plugins/app/package.json +++ b/plugins/app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app", - "version": "0.4.0", + "version": "0.4.1-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "app", diff --git a/plugins/app/src/extensions/AppLanguageApi.ts b/plugins/app/src/extensions/AppLanguageApi.ts index 4f605aa30f..80efa1d9e9 100644 --- a/plugins/app/src/extensions/AppLanguageApi.ts +++ b/plugins/app/src/extensions/AppLanguageApi.ts @@ -16,7 +16,7 @@ // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppLanguageSelector } from '../../../../packages/core-app-api/src/apis/implementations/AppLanguageApi'; -import { appLanguageApiRef } from '@backstage/core-plugin-api/alpha'; +import { appLanguageApiRef } from '@backstage/frontend-plugin-api'; import { ApiBlueprint } from '@backstage/frontend-plugin-api'; export const AppLanguageApi = ApiBlueprint.makeWithOverrides({ diff --git a/plugins/app/src/extensions/TranslationsApi.tsx b/plugins/app/src/extensions/TranslationsApi.tsx index a327aba299..c7f259d135 100644 --- a/plugins/app/src/extensions/TranslationsApi.tsx +++ b/plugins/app/src/extensions/TranslationsApi.tsx @@ -21,7 +21,7 @@ import { TranslationBlueprint } from '@backstage/plugin-app-react'; import { appLanguageApiRef, translationApiRef, -} from '@backstage/core-plugin-api/alpha'; +} from '@backstage/frontend-plugin-api'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { I18nextTranslationApi } from '../../../../packages/core-app-api/src/apis/implementations/TranslationApi/I18nextTranslationApi'; diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 88849b31dc..08e0dac595 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index cc5c8243b9..86a75917e8 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", - "version": "0.4.12", + "version": "0.4.13-next.0", "description": "The atlassian-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md index 9626a18c37..79ff975f48 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 2d39019295..e1d8ef0cd8 100644 --- a/plugins/auth-backend-module-auth0-provider/package.json +++ b/plugins/auth-backend-module-auth0-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-auth0-provider", - "version": "0.3.0", + "version": "0.3.1-next.0", "description": "The auth0-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md index c510c9dcc0..ec48ad5eb2 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.13 ### Patch Changes diff --git a/plugins/auth-backend-module-aws-alb-provider/package.json b/plugins/auth-backend-module-aws-alb-provider/package.json index d61cadd863..e86e425ccd 100644 --- a/plugins/auth-backend-module-aws-alb-provider/package.json +++ b/plugins/auth-backend-module-aws-alb-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-aws-alb-provider", - "version": "0.4.13", + "version": "0.4.14-next.0", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 8583ca3ff0..ae68e22115 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.2.17 ### Patch Changes diff --git a/plugins/auth-backend-module-azure-easyauth-provider/package.json b/plugins/auth-backend-module-azure-easyauth-provider/package.json index 71c5c7366a..78f55326d8 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/package.json +++ b/plugins/auth-backend-module-azure-easyauth-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-azure-easyauth-provider", - "version": "0.2.17", + "version": "0.2.18-next.0", "description": "The azure-easyauth-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md index 365bbb6172..d25a7748a2 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 2584bdf8fa..e5368834e7 100644 --- a/plugins/auth-backend-module-bitbucket-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-provider", - "version": "0.3.12", + "version": "0.3.13-next.0", "description": "The bitbucket-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md index 4bee591f4e..31d965325e 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-server-provider/package.json b/plugins/auth-backend-module-bitbucket-server-provider/package.json index 7dd8b610af..dceb88d24d 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/package.json +++ b/plugins/auth-backend-module-bitbucket-server-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-bitbucket-server-provider", - "version": "0.2.12", + "version": "0.2.13-next.0", "description": "The bitbucket-server-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index e5c120a1e8..22625985a7 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index 3a318f6dd4..cb471664db 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/package.json +++ b/plugins/auth-backend-module-cloudflare-access-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-cloudflare-access-provider", - "version": "0.4.12", + "version": "0.4.13-next.0", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index cc0568608c..1180e9a217 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 029b66a509..29af42c8ae 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", - "version": "0.4.12", + "version": "0.4.13-next.0", "description": "A GCP IAP auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index 528a53ffc7..d864e8389f 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.5.0 ### Minor Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index da0c22725b..e507be91f6 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", - "version": "0.5.0", + "version": "0.5.1-next.0", "description": "The github-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 11352547a4..42c087bf03 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index b933bb50a2..195560d8e9 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", - "version": "0.4.0", + "version": "0.4.1-next.0", "description": "The gitlab-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 4b3ee7ecb0..2d260538af 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 1683c8447f..d9a355d204 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", - "version": "0.3.12", + "version": "0.3.13-next.0", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index c249a36e78..bf229cf304 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.2.16 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 0cda2cd9cd..2b05b628be 100644 --- a/plugins/auth-backend-module-guest-provider/package.json +++ b/plugins/auth-backend-module-guest-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-guest-provider", - "version": "0.2.16", + "version": "0.2.17-next.0", "description": "The guest-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index e5597b1bb2..045decf2fb 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 3bdc28d423..2ad18ac6de 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", - "version": "0.3.12", + "version": "0.3.13-next.0", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 77dcbeb9e5..8b04f8824b 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.4.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.12 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 6dc9f68157..b2b929bb11 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", - "version": "0.4.12", + "version": "0.4.13-next.0", "description": "The oauth2-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index e22f2a783e..2053d99d83 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.2.17 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index c1adcc93fe..299c00ea19 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", - "version": "0.2.17", + "version": "0.2.18-next.0", "description": "The oauth2-proxy-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md index 71936899b9..4acdfe423b 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.27.1-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.4.13 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 813846adcc..662c6dcd58 100644 --- a/plugins/auth-backend-module-oidc-provider/package.json +++ b/plugins/auth-backend-module-oidc-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-oidc-provider", - "version": "0.4.13", + "version": "0.4.14-next.0", "description": "The oidc-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index d8a1fbe809..2bca29cbde 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index 8e7e96a930..021fc5a9cd 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", - "version": "0.2.12", + "version": "0.2.13-next.0", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index 8b1b1a0474..cf8e8e89e5 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index bed4161c81..c36dea44be 100644 --- a/plugins/auth-backend-module-onelogin-provider/package.json +++ b/plugins/auth-backend-module-onelogin-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-onelogin-provider", - "version": "0.3.12", + "version": "0.3.13-next.0", "description": "The onelogin-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-openshift-provider/CHANGELOG.md b/plugins/auth-backend-module-openshift-provider/CHANGELOG.md index aa1dc8fb84..02ae1c6562 100644 --- a/plugins/auth-backend-module-openshift-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-openshift-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-openshift-provider +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/auth-backend-module-openshift-provider/package.json b/plugins/auth-backend-module-openshift-provider/package.json index 35e405e9e5..40b8bdd241 100644 --- a/plugins/auth-backend-module-openshift-provider/package.json +++ b/plugins/auth-backend-module-openshift-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-openshift-provider", - "version": "0.1.4", + "version": "0.1.5-next.0", "description": "The OpenShift backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 9c85d5ae24..10f9e6d561 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.3.11 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index d3206effae..2d05830c78 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", - "version": "0.3.11", + "version": "0.3.12-next.0", "description": "The pinniped-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index 35b2761818..2235daf7e0 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.5.11 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 203234d90c..d0b8034ae7 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", - "version": "0.5.11", + "version": "0.5.12-next.0", "description": "The vmware-cloud-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 9f77de97e7..068a085520 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-auth-backend +## 0.27.1-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- 619be54: Update migrations to be reversible +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + ## 0.27.0 ### Minor Changes diff --git a/plugins/auth-backend/migrations/20200619125845_init.js b/plugins/auth-backend/migrations/20200619125845_init.js index d5fc08ce48..a53ac46ea9 100644 --- a/plugins/auth-backend/migrations/20200619125845_init.js +++ b/plugins/auth-backend/migrations/20200619125845_init.js @@ -42,5 +42,5 @@ exports.up = async function up(knex) { * @param {import('knex').Knex} knex */ exports.down = async function down(knex) { - return knex.schema.dropTable('auth_keystore'); + return knex.schema.dropTable('signing_keys'); }; diff --git a/plugins/auth-backend/migrations/20220321100910_timestamptz_again.js b/plugins/auth-backend/migrations/20220321100910_timestamptz_again.js index ab7e713b96..86a87ebe7c 100644 --- a/plugins/auth-backend/migrations/20220321100910_timestamptz_again.js +++ b/plugins/auth-backend/migrations/20220321100910_timestamptz_again.js @@ -48,7 +48,7 @@ exports.down = async function down(knex) { if (!knex.client.config.client.includes('sqlite3')) { await knex.schema.alterTable('signing_keys', table => { table - .timestamp('created_at', { useTz: false, precision: 0 }) + .timestamp('created_at', { useTz: true, precision: 0 }) .notNullable() .defaultTo(knex.fn.now()) .comment('The creation time of the key') diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index da5f9c4ea6..45d17d6f6d 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.27.0", + "version": "0.27.1-next.0", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", diff --git a/plugins/auth-backend/report.sql.md b/plugins/auth-backend/report.sql.md index 4dc160a2bf..2da5473734 100644 --- a/plugins/auth-backend/report.sql.md +++ b/plugins/auth-backend/report.sql.md @@ -2,9 +2,6 @@ > Do not edit this file. It is a report generated by `yarn build:api-reports` -> [!WARNING] -> Failed to migrate down from '20220321100910_timestamptz_again.js' - ## Table `oauth_authorization_sessions` | Column | Type | Nullable | Max Length | Default | diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index ece86309bd..651d2752d3 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-auth-node +## 0.6.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.6.13 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index c6eb92e607..440f6a4913 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.6.13", + "version": "0.6.14-next.0", "backstage": { "role": "node-library", "pluginId": "auth", diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 6028f0218c..1b8da082e0 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-react +## 0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + ## 0.1.24 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index f61542d1a3..9466e09e19 100644 --- a/plugins/auth-react/package.json +++ b/plugins/auth-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-react", - "version": "0.1.24", + "version": "0.1.25-next.0", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/auth/CHANGELOG.md b/plugins/auth/CHANGELOG.md index e2e1da46d0..469964a57c 100644 --- a/plugins/auth/CHANGELOG.md +++ b/plugins/auth/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + ## 0.1.5 ### Patch Changes diff --git a/plugins/auth/package.json b/plugins/auth/package.json index 23484cc5e5..02d5073f2b 100644 --- a/plugins/auth/package.json +++ b/plugins/auth/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth", - "version": "0.1.5", + "version": "0.1.6-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "auth", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 134a370bda..9ad8a14276 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.3.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + ## 0.3.7 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index e40040081a..41f7f8b49e 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.3.7", + "version": "0.3.8-next.0", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 84d0ffe183..104db8bed8 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-kubernetes-common@0.9.10 + ## 0.4.20 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index efcb7f76cd..657190a2ac 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", - "version": "0.4.20", + "version": "0.4.21-next.0", "description": "A Backstage catalog backend module that helps integrate towards AWS", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index cd350fb453..71ffc6eb5f 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.3.14 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index bb5291ef9a..c73d71073a 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", - "version": "0.3.14", + "version": "0.3.15-next.0", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index b75a3831e4..44454b6645 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + ## 0.5.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 948e0f0cdf..69a41a3a2a 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.5.11", + "version": "0.5.12-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index b1acf9790a..570ed41256 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-bitbucket-cloud-common@0.3.8-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.5.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index ebfd1104bd..1f7bd194be 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", - "version": "0.5.8", + "version": "0.5.9-next.0", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 925debc5c0..92bb46d3c0 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.5.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index fb0df6172c..8f4e3b97b5 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.5.8", + "version": "0.5.9-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index d1e8b8cc13..210468d544 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-kubernetes-common@0.9.10 + ## 0.3.16 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 446769a5df..51c6791c36 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", - "version": "0.3.16", + "version": "0.3.17-next.0", "description": "A Backstage catalog backend module that helps integrate towards GCP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gcp/report.api.md b/plugins/catalog-backend-module-gcp/report.api.md index 6260d07c88..784de87d2e 100644 --- a/plugins/catalog-backend-module-gcp/report.api.md +++ b/plugins/catalog-backend-module-gcp/report.api.md @@ -20,22 +20,13 @@ export class GkeEntityProvider implements EntityProvider { // (undocumented) connect(connection: EntityProviderConnection): Promise; // (undocumented) - static fromConfig({ - logger, - scheduler, - config, - }: { + static fromConfig(input: { logger: LoggerService; scheduler: SchedulerService; config: Config; }): GkeEntityProvider; // (undocumented) - static fromConfigWithClient({ - logger, - scheduler, - config, - clusterManagerClient, - }: { + static fromConfigWithClient(input: { logger: LoggerService; scheduler: SchedulerService; config: Config; diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 3eaee80cc6..6a14e2fa96 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.3.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 72d28a5f13..e2b12b1872 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.3.11", + "version": "0.3.12-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", diff --git a/plugins/catalog-backend-module-gitea/CHANGELOG.md b/plugins/catalog-backend-module-gitea/CHANGELOG.md index 92dd71ee81..b7c152b7ec 100644 --- a/plugins/catalog-backend-module-gitea/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-gitea +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.1.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitea/package.json b/plugins/catalog-backend-module-gitea/package.json index 044f074c9e..9d23fa2ca0 100644 --- a/plugins/catalog-backend-module-gitea/package.json +++ b/plugins/catalog-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitea", - "version": "0.1.9", + "version": "0.1.10-next.0", "description": "The gitea backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index f537919ae8..fd442dab13 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.12.3-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.3.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index b302739caf..be85ed65a3 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", - "version": "0.3.19", + "version": "0.3.20-next.0", "description": "The github-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index d0d993a928..586ea98c43 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-github +## 0.12.3-next.0 + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.12.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 5787333e52..fdef1a8aab 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-github", - "version": "0.12.2", + "version": "0.12.3-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index 8826f23fe9..3584e8ce8c 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-gitlab@0.8.1-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index ff0cd55ce0..19d2bd5aa4 100644 --- a/plugins/catalog-backend-module-gitlab-org/package.json +++ b/plugins/catalog-backend-module-gitlab-org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab-org", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The gitlab-org backend module for the catalog plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 2bfa7c354c..e8ee9a0b17 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.8.1-next.0 + +### Patch Changes + +- d933f62: Add configurable throttling and retry mechanism for GitLab integration. +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.8.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index b0dad1bef8..88661729b2 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", - "version": "0.8.0", + "version": "0.8.1-next.0", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index c7d4c8b3ae..c30dc39d18 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.7.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + ## 0.7.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 5ad2ecf499..d03ac523c3 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", - "version": "0.7.9", + "version": "0.7.10-next.0", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 5db5d368e0..b9959ad209 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.12.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.12.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index cf3e12c297..9b1ff77957 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", - "version": "0.12.2", + "version": "0.12.3-next.0", "description": "A Backstage catalog backend module that helps integrate towards LDAP", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 04b21b02b8..9520d32d3f 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@3.5.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index 5bd890359c..d3c65991a2 100644 --- a/plugins/catalog-backend-module-logs/package.json +++ b/plugins/catalog-backend-module-logs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-logs", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "A module that subscribes to catalog related events and logs them.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 82a20987bc..5e525e9f0e 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.9.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 4791527b95..14ccfbef18 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", - "version": "0.9.0", + "version": "0.9.1-next.0", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index f985321a83..69cd786a0a 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.2.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 42650d9e8e..2ab5d94ff6 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", - "version": "0.2.19", + "version": "0.2.20-next.0", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index ed5a970212..28d5bec889 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.2.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index bdeee6b26e..8ae9637017 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", - "version": "0.2.19", + "version": "0.2.20-next.0", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 7ddee70b70..c5b40cc991 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + ## 0.2.17 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 0dcc437ef9..df180ee6bc 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", - "version": "0.2.17", + "version": "0.2.18-next.0", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 748c191e84..31f4f425fa 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.6.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.13 + - @backstage/plugin-permission-common@0.9.6 + ## 0.6.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 2c1ea51ce4..748c6a081e 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", - "version": "0.6.8", + "version": "0.6.9-next.0", "description": "Backstage Catalog module to view unprocessed entities", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 4431c15402..cbca2a2b92 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-catalog-backend +## 3.5.0-next.0 + +### Minor Changes + +- bf71677: Added opentelemetry metrics for SCM events: + + - `catalog.events.scm.messages` with attribute `eventType`: Counter for the number of SCM events actually received by the catalog backend. The `eventType` is currently either `location` or `repository`. + +### Patch Changes + +- 6738cf0: build(deps): bump `minimatch` from 9.0.5 to 10.2.1 +- fbf382f: Minor internal optimisation +- 1ee5b28: Migrates existing catalog metrics to use the alpha MetricsService. This release is a 1:1 migration with no breaking changes. +- 3181973: Changed the `search` table foreign key to point to `final_entities` instead of `refresh_state` +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 3.4.0 ### Minor Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 8cb7b8f64d..b1f0175c81 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "3.4.0", + "version": "3.5.0-next.0", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts index 790762a428..b9f3599b19 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts @@ -36,6 +36,7 @@ import { createRandomProcessingInterval } from '../processing/refresh'; import { timestampToDateTime } from './conversion'; import { generateStableHash } from './util'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; jest.setTimeout(60_000); @@ -59,6 +60,7 @@ describe('DefaultProcessingDatabase', () => { maxSeconds: 150, }), events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }), }; } diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts index a421ca19b2..264c11055d 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts @@ -47,6 +47,7 @@ import { DateTime } from 'luxon'; import { CATALOG_CONFLICTS_TOPIC } from '../constants'; import { CatalogConflictEventPayload } from '../catalog/types'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; // The number of items that are sent per batch to the database layer, when // doing .batchInsert calls to knex. This needs to be low enough to not cause @@ -60,6 +61,7 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { logger: LoggerService; refreshInterval: ProcessingIntervalFunction; events: EventsService; + metrics: MetricsService; }; constructor(options: { @@ -67,9 +69,10 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { logger: LoggerService; refreshInterval: ProcessingIntervalFunction; events: EventsService; + metrics: MetricsService; }) { this.options = options; - initDatabaseMetrics(options.database); + initDatabaseMetrics(options.database, options.metrics); } async updateProcessedEntity( diff --git a/plugins/catalog-backend/src/database/metrics.ts b/plugins/catalog-backend/src/database/metrics.ts index 809405d69f..f6a1464b3a 100644 --- a/plugins/catalog-backend/src/database/metrics.ts +++ b/plugins/catalog-backend/src/database/metrics.ts @@ -17,12 +17,12 @@ import { Knex } from 'knex'; import { createGaugeMetric } from '../util/metrics'; import { DbRelationsRow, DbLocationsRow, DbSearchRow } from './tables'; -import { metrics } from '@opentelemetry/api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; -export function initDatabaseMetrics(knex: Knex) { +export function initDatabaseMetrics(knex: Knex, metrics: MetricsService) { const seenProm = new Set(); const seen = new Set(); - const meter = metrics.getMeter('default'); + return { entities_count_prom: createGaugeMetric({ name: 'catalog_entities_count', @@ -69,7 +69,7 @@ export function initDatabaseMetrics(knex: Knex) { this.set(Number(total[0].count)); }, }), - entities_count: meter + entities_count: metrics .createObservableGauge('catalog_entities_count', { description: 'Total amount of entities in the catalog', }) @@ -93,7 +93,7 @@ export function initDatabaseMetrics(knex: Knex) { } }); }), - registered_locations: meter + registered_locations: metrics .createObservableGauge('catalog_registered_locations_count', { description: 'Total amount of registered locations in the catalog', }) @@ -113,7 +113,7 @@ export function initDatabaseMetrics(knex: Knex) { gauge.observe(Number(total[0].count)); } }), - relations: meter + relations: metrics .createObservableGauge('catalog_relations_count', { description: 'Total amount of relations between entities', }) diff --git a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts index d26fb8d6d4..e4172e8cdf 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts @@ -17,33 +17,11 @@ import { Knex } from 'knex'; import splitToChunks from 'lodash/chunk'; import { v4 as uuid } from 'uuid'; -import { ErrorLike, isError } from '@backstage/errors'; import { StitchingStrategy } from '../../../stitching/types'; -import { setTimeout as sleep } from 'node:timers/promises'; import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; +import { retryOnDeadlock } from '../../util'; const UPDATE_CHUNK_SIZE = 100; // Smaller chunks reduce contention -const DEADLOCK_RETRY_ATTEMPTS = 3; -const DEADLOCK_BASE_DELAY_MS = 25; - -// PostgreSQL deadlock error code -const POSTGRES_DEADLOCK_SQLSTATE = '40P01'; - -/** - * Checks if the given error is a deadlock error for the database engine in use. - */ -function isDeadlockError( - knex: Knex | Knex.Transaction, - e: unknown, -): e is ErrorLike { - if (knex.client.config.client.includes('pg')) { - // PostgreSQL deadlock detection - return isError(e) && e.code === POSTGRES_DEADLOCK_SQLSTATE; - } - - // Add more database engine checks here as needed - return false; -} /** * Marks a number of entities for stitching some time in the near @@ -69,12 +47,7 @@ export async function markForStitching(options: { .update({ hash: 'force-stitching', }) - .whereIn( - 'entity_id', - knex('refresh_state') - .select('entity_id') - .whereIn('entity_ref', chunk), - ); + .whereIn('entity_ref', chunk); await retryOnDeadlock(async () => { await knex .table('refresh_state') @@ -143,24 +116,3 @@ function sortSplit(input: Iterable | undefined): string[][] { array.sort(); return splitToChunks(array, UPDATE_CHUNK_SIZE); } - -async function retryOnDeadlock( - fn: () => Promise, - knex: Knex | Knex.Transaction, - retries = DEADLOCK_RETRY_ATTEMPTS, - baseMs = DEADLOCK_BASE_DELAY_MS, -): Promise { - let attempt = 0; - for (;;) { - try { - return await fn(); - } catch (e: unknown) { - if (isDeadlockError(knex, e) && attempt < retries) { - await sleep(baseMs * Math.pow(2, attempt)); - attempt++; - continue; - } - throw e; - } - } -} diff --git a/plugins/catalog-backend/src/database/util.test.ts b/plugins/catalog-backend/src/database/util.test.ts new file mode 100644 index 0000000000..b3f11b7f92 --- /dev/null +++ b/plugins/catalog-backend/src/database/util.test.ts @@ -0,0 +1,125 @@ +/* + * Copyright 2026 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 { Knex } from 'knex'; +import { retryOnDeadlock } from './util'; + +jest.mock('node:timers/promises', () => ({ + setTimeout: jest.fn(), +})); + +function mockKnex(client: string): Knex { + return { client: { config: { client } } } as unknown as Knex; +} + +function pgDeadlockError(): Error & { code: string } { + const err = new Error('deadlock detected') as Error & { code: string }; + err.code = '40P01'; + return err; +} + +describe('retryOnDeadlock', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('returns the result on success', async () => { + const fn = jest.fn().mockResolvedValue('ok'); + const result = await retryOnDeadlock(fn, mockKnex('pg'), 3, 1); + expect(result).toBe('ok'); + expect(fn).toHaveBeenCalledTimes(1); + }); + + it('retries on PostgreSQL deadlock errors', async () => { + const fn = jest + .fn() + .mockRejectedValueOnce(pgDeadlockError()) + .mockRejectedValueOnce(pgDeadlockError()) + .mockResolvedValue('recovered'); + + const result = await retryOnDeadlock(fn, mockKnex('pg'), 3, 1); + expect(result).toBe('recovered'); + expect(fn).toHaveBeenCalledTimes(3); + }); + + it('throws after exhausting all retries', async () => { + const fn = jest.fn().mockRejectedValue(pgDeadlockError()); + + await expect(retryOnDeadlock(fn, mockKnex('pg'), 3, 1)).rejects.toThrow( + 'deadlock detected', + ); + // 1 initial + 3 retries = 4 calls + expect(fn).toHaveBeenCalledTimes(4); + }); + + it('does not retry non-deadlock errors on PostgreSQL', async () => { + const err = new Error('something else'); + const fn = jest.fn().mockRejectedValue(err); + + await expect(retryOnDeadlock(fn, mockKnex('pg'), 3, 1)).rejects.toThrow( + 'something else', + ); + expect(fn).toHaveBeenCalledTimes(1); + }); + + it('does not retry deadlock-like errors on non-PostgreSQL engines', async () => { + const fn = jest.fn().mockRejectedValue(pgDeadlockError()); + + await expect( + retryOnDeadlock(fn, mockKnex('better-sqlite3'), 3, 1), + ).rejects.toThrow('deadlock detected'); + expect(fn).toHaveBeenCalledTimes(1); + }); + + it('applies exponential backoff between retries', async () => { + const { setTimeout: sleep } = jest.requireMock<{ + setTimeout: jest.Mock; + }>('node:timers/promises'); + + const fnCallsAtSleep: number[] = []; + const fn = jest + .fn() + .mockRejectedValueOnce(pgDeadlockError()) + .mockRejectedValueOnce(pgDeadlockError()) + .mockRejectedValueOnce(pgDeadlockError()) + .mockResolvedValue('done'); + + sleep.mockImplementation(async () => { + fnCallsAtSleep.push(fn.mock.calls.length); + }); + + const baseMs = 50; + const result = await retryOnDeadlock(fn, mockKnex('pg'), 3, baseMs); + + expect(result).toBe('done'); + expect(fn).toHaveBeenCalledTimes(4); + // Each sleep happens after fn has been called N times + expect(fnCallsAtSleep).toEqual([1, 2, 3]); + expect(sleep).toHaveBeenCalledTimes(3); + expect(sleep).toHaveBeenNthCalledWith(1, 50); + expect(sleep).toHaveBeenNthCalledWith(2, 100); + expect(sleep).toHaveBeenNthCalledWith(3, 200); + }); + + it('defaults to 3 retries when not specified', async () => { + const fn = jest.fn().mockRejectedValue(pgDeadlockError()); + + await expect(retryOnDeadlock(fn, mockKnex('pg'))).rejects.toThrow( + 'deadlock detected', + ); + expect(fn).toHaveBeenCalledTimes(4); + }); +}); diff --git a/plugins/catalog-backend/src/database/util.ts b/plugins/catalog-backend/src/database/util.ts index 3734670a41..39dc69c025 100644 --- a/plugins/catalog-backend/src/database/util.ts +++ b/plugins/catalog-backend/src/database/util.ts @@ -15,8 +15,11 @@ */ import { Entity } from '@backstage/catalog-model'; -import { createHash } from 'node:crypto'; +import { ErrorLike, isError } from '@backstage/errors'; import stableStringify from 'fast-json-stable-stringify'; +import { Knex } from 'knex'; +import { createHash } from 'node:crypto'; +import { setTimeout as sleep } from 'node:timers/promises'; export function generateStableHash(entity: Entity) { return createHash('sha1') @@ -31,3 +34,43 @@ export function generateTargetKey(target: string) { .digest('hex')}` : target; } + +/** + * Retries an operation on database deadlock errors. + */ +export async function retryOnDeadlock( + fn: () => Promise, + knex: Knex | Knex.Transaction, + retries = 3, + baseMs = 25, +): Promise { + let attempt = 0; + for (;;) { + try { + return await fn(); + } catch (e: unknown) { + if (isDeadlockError(knex, e) && attempt < retries) { + await sleep(baseMs * Math.pow(2, attempt)); + attempt++; + continue; + } + throw e; + } + } +} + +/** + * Checks if the given error is a deadlock error for the database engine in use. + */ +function isDeadlockError( + knex: Knex | Knex.Transaction, + e: unknown, +): e is ErrorLike { + if (knex.client.config.client.includes('pg')) { + // PostgreSQL deadlock detection via error code + return isError(e) && e.code === '40P01'; + } + + // Add more database engine checks here as needed + return false; +} diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts index ae23830712..88829fc448 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts @@ -23,6 +23,7 @@ import { CatalogProcessingOrchestrator } from './types'; import { Stitcher } from '../stitching/types'; import { ConfigReader } from '@backstage/config'; import { mockServices } from '@backstage/backend-test-utils'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; describe('DefaultCatalogProcessingEngine', () => { const db = { @@ -72,6 +73,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, scheduler: mockServices.scheduler(), events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -141,6 +143,7 @@ describe('DefaultCatalogProcessingEngine', () => { scheduler: mockServices.scheduler(), createHash: () => hash, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -226,6 +229,7 @@ describe('DefaultCatalogProcessingEngine', () => { scheduler: mockServices.scheduler(), createHash: () => hash, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -305,6 +309,7 @@ describe('DefaultCatalogProcessingEngine', () => { scheduler: mockServices.scheduler(), createHash: () => hash, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -367,6 +372,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, pollingIntervalMs: 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -484,6 +490,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, pollingIntervalMs: 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -591,6 +598,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, pollingIntervalMs: 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -676,6 +684,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, pollingIntervalMs: 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); @@ -766,6 +775,7 @@ describe('DefaultCatalogProcessingEngine', () => { createHash: () => hash, pollingIntervalMs: 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); db.transaction.mockImplementation(cb => cb((() => {}) as any)); diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts index 3bcd4fcf44..9416fceea1 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts @@ -23,7 +23,7 @@ import { assertError, serializeError, stringifyError } from '@backstage/errors'; import { Hash } from 'node:crypto'; import stableStringify from 'fast-json-stable-stringify'; import { Knex } from 'knex'; -import { metrics, trace } from '@opentelemetry/api'; +import { trace } from '@opentelemetry/api'; import { ProcessingDatabase, RefreshStateItem } from '../database/types'; import { createCounterMetric, createSummaryMetric } from '../util/metrics'; import { CatalogProcessingOrchestrator, EntityProcessingResult } from './types'; @@ -39,6 +39,7 @@ import { deleteOrphanedEntities } from '../database/operations/util/deleteOrphan import { EventsService } from '@backstage/plugin-events-node'; import { CATALOG_ERRORS_TOPIC } from '../constants'; import { LoggerService, SchedulerService } from '@backstage/backend-plugin-api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; const CACHE_TTL = 5; @@ -94,6 +95,7 @@ export class DefaultCatalogProcessingEngine { }) => Promise | void; tracker?: ProgressTracker; events: EventsService; + metrics: MetricsService; }) { this.config = options.config; this.scheduler = options.scheduler; @@ -106,7 +108,7 @@ export class DefaultCatalogProcessingEngine { this.pollingIntervalMs = options.pollingIntervalMs ?? 1_000; this.orphanCleanupIntervalMs = options.orphanCleanupIntervalMs ?? 30_000; this.onProcessingError = options.onProcessingError; - this.tracker = options.tracker ?? progressTracker(); + this.tracker = options.tracker ?? progressTracker(options.metrics); this.events = options.events; this.stopFunc = undefined; @@ -386,7 +388,7 @@ export class DefaultCatalogProcessingEngine { } // Helps wrap the timing and logging behaviors -function progressTracker() { +function progressTracker(metrics: MetricsService) { // prom-client metrics are deprecated in favour of OpenTelemetry metrics. const promProcessedEntities = createCounterMetric({ name: 'catalog_processed_entities_count', @@ -408,13 +410,12 @@ function progressTracker() { help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead', }); - const meter = metrics.getMeter('default'); - const processedEntities = meter.createCounter( + const processedEntities = metrics.createCounter( 'catalog.processed.entities.count', { description: 'Amount of entities processed' }, ); - const processingDuration = meter.createHistogram( + const processingDuration = metrics.createHistogram( 'catalog.processing.duration', { description: 'Time spent executing the full processing flow', @@ -422,7 +423,7 @@ function progressTracker() { }, ); - const processorsDuration = meter.createHistogram( + const processorsDuration = metrics.createHistogram( 'catalog.processors.duration', { description: 'Time spent executing catalog processors', @@ -430,7 +431,7 @@ function progressTracker() { }, ); - const processingQueueDelay = meter.createHistogram( + const processingQueueDelay = metrics.createHistogram( 'catalog.processing.queue.delay', { description: diff --git a/plugins/catalog-backend/src/providers/DefaultLocationStore.test.ts b/plugins/catalog-backend/src/providers/DefaultLocationStore.test.ts index f12293fa1f..e1bd8ec386 100644 --- a/plugins/catalog-backend/src/providers/DefaultLocationStore.test.ts +++ b/plugins/catalog-backend/src/providers/DefaultLocationStore.test.ts @@ -35,6 +35,7 @@ describe('DefaultLocationStore', () => { const mockScmEvents = { subscribe: jest.fn(), publish: jest.fn(), + markEventActionTaken: jest.fn(), }; let subscriber: CatalogScmEventsServiceSubscriber | undefined; @@ -362,6 +363,11 @@ describe('DefaultLocationStore', () => { }, ], }); + + expect(mockScmEvents.markEventActionTaken).toHaveBeenCalledWith({ + count: 1, + action: 'delete', + }); }); }); @@ -483,6 +489,15 @@ describe('DefaultLocationStore', () => { ], removed: [], }); + + expect(mockScmEvents.markEventActionTaken).toHaveBeenCalledWith({ + count: 1, + action: 'delete', + }); + expect(mockScmEvents.markEventActionTaken).toHaveBeenCalledWith({ + count: 1, + action: 'create', + }); }); }); @@ -589,6 +604,11 @@ describe('DefaultLocationStore', () => { }, ], }); + + expect(mockScmEvents.markEventActionTaken).toHaveBeenCalledWith({ + count: 1, + action: 'delete', + }); }); }); @@ -709,6 +729,11 @@ describe('DefaultLocationStore', () => { ], removed: [], }); + + expect(mockScmEvents.markEventActionTaken).toHaveBeenCalledWith({ + count: 1, + action: 'move', + }); }); }); }); diff --git a/plugins/catalog-backend/src/providers/DefaultLocationStore.ts b/plugins/catalog-backend/src/providers/DefaultLocationStore.ts index 305bd611dc..bfd4270696 100644 --- a/plugins/catalog-backend/src/providers/DefaultLocationStore.ts +++ b/plugins/catalog-backend/src/providers/DefaultLocationStore.ts @@ -305,16 +305,40 @@ export class DefaultLocationStore implements LocationStore, EntityProvider { } if (exactLocationsToDelete.size > 0) { - await this.#deleteLocationsByExactUrl(exactLocationsToDelete); + const count = await this.#deleteLocationsByExactUrl( + exactLocationsToDelete, + ); + this.scmEvents.markEventActionTaken({ + count, + action: 'delete', + }); } if (locationPrefixesToDelete.size > 0) { - await this.#deleteLocationsByUrlPrefix(locationPrefixesToDelete); + const count = await this.#deleteLocationsByUrlPrefix( + locationPrefixesToDelete, + ); + this.scmEvents.markEventActionTaken({ + count, + action: 'delete', + }); } if (exactLocationsToCreate.size > 0) { - await this.#createLocationsByExactUrl(exactLocationsToCreate); + const count = await this.#createLocationsByExactUrl( + exactLocationsToCreate, + ); + this.scmEvents.markEventActionTaken({ + count, + action: 'create', + }); } if (locationPrefixesToMove.size > 0) { - await this.#moveLocationsByUrlPrefix(locationPrefixesToMove); + const count = await this.#moveLocationsByUrlPrefix( + locationPrefixesToMove, + ); + this.scmEvents.markEventActionTaken({ + count, + action: 'move', + }); } } diff --git a/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.test.ts b/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.test.ts index fb54caab1b..e6c1c701d3 100644 --- a/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.test.ts +++ b/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.test.ts @@ -50,6 +50,7 @@ describe('GenericScmEventRefreshProvider', () => { return { unsubscribe: () => {} }; }), publish: jest.fn(), + markEventActionTaken: jest.fn(), }; const store = new GenericScmEventRefreshProvider(knex, scmEvents, { diff --git a/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.ts b/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.ts index 9d62ef1bdf..31cb6eb62b 100644 --- a/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.ts +++ b/plugins/catalog-backend/src/providers/GenericScmEventRefreshProvider.ts @@ -150,6 +150,8 @@ export class GenericScmEventRefreshProvider implements EntityProvider { count += Number(result); } + + this.#scmEvents.markEventActionTaken({ count, action: 'refresh' }); } } diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index e3d0c26b0f..d0f2442f0c 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -117,6 +117,7 @@ import { import { filterAndSortProcessors, filterProviders } from './util'; import { GenericScmEventRefreshProvider } from '../providers/GenericScmEventRefreshProvider'; import { readScmEventHandlingConfig } from '../util/readScmEventHandlingConfig'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; export type CatalogEnvironment = { logger: LoggerService; @@ -131,6 +132,7 @@ export type CatalogEnvironment = { auditor: AuditorService; events: EventsService; catalogScmEvents: CatalogScmEventsService; + metrics: MetricsService; }; /** @@ -429,6 +431,7 @@ export class CatalogBuilder { httpAuth, events, catalogScmEvents, + metrics, } = this.env; const enableRelationsCompatibility = Boolean( @@ -448,6 +451,7 @@ export class CatalogBuilder { const stitcher = DefaultStitcher.fromConfig(config, { knex: dbClient, logger, + metrics, }); const processingDatabase = new DefaultProcessingDatabase({ @@ -455,6 +459,7 @@ export class CatalogBuilder { logger, events, refreshInterval: this.processingInterval, + metrics, }); const providerDatabase = new DefaultProviderDatabase({ database: dbClient, @@ -577,6 +582,7 @@ export class CatalogBuilder { this.onProcessingError?.(event); }, events, + metrics, }); const locationAnalyzer = diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 26b09b9eea..915dd80dd9 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -45,7 +45,10 @@ import { eventsServiceRef } from '@backstage/plugin-events-node'; import { Permission } from '@backstage/plugin-permission-common'; import { merge } from 'lodash'; import { CatalogBuilder } from './CatalogBuilder'; -import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { + actionsRegistryServiceRef, + metricsServiceRef, +} from '@backstage/backend-plugin-api/alpha'; import { createCatalogActions } from '../actions'; import type { EntityProviderEntry } from '../processing/connectEntityProviders'; @@ -219,6 +222,7 @@ export const catalogPlugin = createBackendPlugin({ catalog: catalogServiceRef, actionsRegistry: actionsRegistryServiceRef, catalogScmEvents: catalogScmEventsServiceRef, + metrics: metricsServiceRef, }, async init({ logger, @@ -237,6 +241,7 @@ export const catalogPlugin = createBackendPlugin({ auditor, events, catalogScmEvents, + metrics, }) { const builder = await CatalogBuilder.create({ config, @@ -251,6 +256,7 @@ export const catalogPlugin = createBackendPlugin({ auditor, events, catalogScmEvents, + metrics, }); if (onProcessingError) { @@ -301,6 +307,22 @@ export const catalogPlugin = createBackendPlugin({ catalog, actionsRegistry, }); + + const scmEventsMessagesCounter = metrics.createCounter<{ + eventType: string; + }>('catalog.events.scm.messages', { + description: + 'Number of SCM event messages received by the catalog backend', + unit: 'short', + }); + catalogScmEvents.subscribe({ + onEvents: async e => { + for (const event of e) { + const eventType = event.type.split('.')[0]; + scmEventsMessagesCounter.add(1, { eventType }); + } + }, + }); }, }); }, diff --git a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts index fffe2467b5..00ce749b4a 100644 --- a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts +++ b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts @@ -38,6 +38,7 @@ import { DefaultRefreshService } from './DefaultRefreshService'; import { ConfigReader } from '@backstage/config'; import { DefaultStitcher } from '../stitching/DefaultStitcher'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; jest.setTimeout(60_000); @@ -58,6 +59,7 @@ describe('DefaultRefreshService', () => { logger, refreshInterval: () => 100, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }), catalogDb: new DefaultCatalogDatabase({ database: knex, @@ -115,6 +117,7 @@ describe('DefaultRefreshService', () => { const stitcher = DefaultStitcher.fromConfig(new ConfigReader({}), { knex, logger: defaultLogger, + metrics: metricsServiceMock.mock(), }); const engine = new DefaultCatalogProcessingEngine({ config: new ConfigReader({}), @@ -164,6 +167,7 @@ describe('DefaultRefreshService', () => { createHash: () => createHash('sha1'), pollingIntervalMs: 50, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); return engine; diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index aa3ed3a551..e13d33d58d 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -1429,6 +1429,7 @@ describe('POST /locations/by-query works end to end', () => { const mockScmEvents = { subscribe: jest.fn(), publish: jest.fn(), + markEventActionTaken: jest.fn(), }; const store = new DefaultLocationStore(knex, mockScmEvents, { diff --git a/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts index 251aaa9080..88acf68dd3 100644 --- a/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts +++ b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts @@ -25,6 +25,7 @@ import { DbSearchRow, } from '../database/tables'; import { DefaultStitcher } from './DefaultStitcher'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; jest.setTimeout(60_000); @@ -42,6 +43,7 @@ describe('Stitcher', () => { knex: db, logger, strategy: { mode: 'immediate' }, + metrics: metricsServiceMock.mock(), }); let entities: DbFinalEntitiesRow[]; let entity: Entity; diff --git a/plugins/catalog-backend/src/stitching/DefaultStitcher.ts b/plugins/catalog-backend/src/stitching/DefaultStitcher.ts index 14b3eca0d4..e7848961a6 100644 --- a/plugins/catalog-backend/src/stitching/DefaultStitcher.ts +++ b/plugins/catalog-backend/src/stitching/DefaultStitcher.ts @@ -31,6 +31,7 @@ import { stitchingStrategyFromConfig, } from './types'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; type DeferredStitchItem = Awaited< ReturnType @@ -55,11 +56,13 @@ export class DefaultStitcher implements Stitcher { options: { knex: Knex; logger: LoggerService; + metrics: MetricsService; }, ): DefaultStitcher { return new DefaultStitcher({ knex: options.knex, logger: options.logger, + metrics: options.metrics, strategy: stitchingStrategyFromConfig(config), }); } @@ -67,12 +70,17 @@ export class DefaultStitcher implements Stitcher { constructor(options: { knex: Knex; logger: LoggerService; + metrics: MetricsService; strategy: StitchingStrategy; }) { this.knex = options.knex; this.logger = options.logger; this.strategy = options.strategy; - this.tracker = progressTracker(options.knex, options.logger); + this.tracker = progressTracker( + options.knex, + options.logger, + options.metrics, + ); } async stitch(options: { diff --git a/plugins/catalog-backend/src/stitching/progressTracker.ts b/plugins/catalog-backend/src/stitching/progressTracker.ts index 9e00a1a01b..f460a17a51 100644 --- a/plugins/catalog-backend/src/stitching/progressTracker.ts +++ b/plugins/catalog-backend/src/stitching/progressTracker.ts @@ -15,31 +15,33 @@ */ import { stringifyError } from '@backstage/errors'; -import { metrics } from '@opentelemetry/api'; import { Knex } from 'knex'; import { DateTime } from 'luxon'; import { DbRefreshStateRow } from '../database/tables'; import { createCounterMetric } from '../util/metrics'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; // Helps wrap the timing and logging behaviors -export function progressTracker(knex: Knex, logger: LoggerService) { +export function progressTracker( + knex: Knex, + logger: LoggerService, + metrics: MetricsService, +) { // prom-client metrics are deprecated in favour of OpenTelemetry metrics. const promStitchedEntities = createCounterMetric({ name: 'catalog_stitched_entities_count', help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead', }); - const meter = metrics.getMeter('default'); - - const stitchedEntities = meter.createCounter( + const stitchedEntities = metrics.createCounter( 'catalog.stitched.entities.count', { description: 'Amount of entities stitched', }, ); - const stitchingDuration = meter.createHistogram( + const stitchingDuration = metrics.createHistogram( 'catalog.stitching.duration', { description: 'Time spent executing the full stitching flow', @@ -47,7 +49,7 @@ export function progressTracker(knex: Knex, logger: LoggerService) { }, ); - const stitchingQueueCount = meter.createObservableGauge( + const stitchingQueueCount = metrics.createObservableGauge( 'catalog.stitching.queue.length', { description: 'Number of entities currently in the stitching queue' }, ); @@ -58,7 +60,7 @@ export function progressTracker(knex: Knex, logger: LoggerService) { result.observe(Number(total[0].count)); }); - const stitchingQueueDelay = meter.createHistogram( + const stitchingQueueDelay = metrics.createHistogram( 'catalog.stitching.queue.delay', { description: diff --git a/plugins/catalog-backend/src/tests/integration.test.ts b/plugins/catalog-backend/src/tests/integration.test.ts index a213d41efb..d03a23f896 100644 --- a/plugins/catalog-backend/src/tests/integration.test.ts +++ b/plugins/catalog-backend/src/tests/integration.test.ts @@ -56,6 +56,7 @@ import { mockServices, TestDatabases } from '@backstage/backend-test-utils'; import { LoggerService } from '@backstage/backend-plugin-api'; import { entitiesResponseToObjects } from '../service/response'; import { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; const voidLogger = mockServices.logger.mock(); @@ -248,6 +249,7 @@ class TestHarness { logger, events: mockServices.events.mock(), refreshInterval: () => 0.05, + metrics: metricsServiceMock.mock(), }); const integrations = ScmIntegrations.fromConfig(config); @@ -280,6 +282,7 @@ class TestHarness { const stitcher = DefaultStitcher.fromConfig(config, { knex: options.db, logger, + metrics: metricsServiceMock.mock(), }); const catalog = new DefaultEntitiesCatalog({ database: options.db, @@ -306,6 +309,7 @@ class TestHarness { }, tracker: proxyProgressTracker, events: mockServices.events.mock(), + metrics: metricsServiceMock.mock(), }); const refresh = new DefaultRefreshService({ database: catalogDatabase }); diff --git a/plugins/catalog-backend/src/tests/performance/getProcessableEntitiesPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/getProcessableEntitiesPerformance.test.ts index 6efa3abbc7..53991e4416 100644 --- a/plugins/catalog-backend/src/tests/performance/getProcessableEntitiesPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/getProcessableEntitiesPerformance.test.ts @@ -19,6 +19,7 @@ import { Knex } from 'knex'; import { DefaultProcessingDatabase } from '../../database/DefaultProcessingDatabase'; import { applyDatabaseMigrations } from '../../database/migrations'; import { describePerformanceTest, performanceTraceEnabled } from './lib/env'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; // #region Helpers @@ -81,6 +82,7 @@ describePerformanceTest('getProcessableEntities', () => { logger: mockServices.logger.mock(), events: mockServices.events.mock(), refreshInterval: () => 0, + metrics: metricsServiceMock.mock(), }); const start = Date.now(); diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index e9cfd3fc59..80fcb546b8 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graph +## 0.5.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + ## 0.5.7 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index e6cef531e1..9b94d69113 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.5.7", + "version": "0.5.8-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index f0bc160164..139b565af2 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.13.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.13.10 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index a481fe889c..52b8379ed5 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.13.10", + "version": "0.13.11-next.0", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 1e2d35507f..22db08b9b9 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-node +## 2.1.0-next.0 + +### Minor Changes + +- bf71677: Added the ability for SCM events subscribers to mark the fact that they have taken actions based on events, which produces output metrics: + + - `catalog.events.scm.actions` with attribute `action`: Counter for the number of actions actually taken by catalog internals or other subscribers, based on SCM events. The `action` is currently either `create`, `delete`, `refresh`, or `move`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/backend-test-utils@1.11.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 2.0.0 ### Minor Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index f8ce28451b..9d37ae31ed 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "2.0.0", + "version": "2.1.0-next.0", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", @@ -68,6 +68,7 @@ "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^", + "@opentelemetry/api": "^1.9.0", "lodash": "^4.17.21", "yaml": "^2.0.0" }, diff --git a/plugins/catalog-node/report-alpha.api.md b/plugins/catalog-node/report-alpha.api.md index aad7518921..0598834c67 100644 --- a/plugins/catalog-node/report-alpha.api.md +++ b/plugins/catalog-node/report-alpha.api.md @@ -125,6 +125,7 @@ export type CatalogScmEventContext = { // @alpha export interface CatalogScmEventsService { + markEventActionTaken(options: { count?: number; action: string }): void; publish(events: CatalogScmEvent[]): Promise; subscribe(subscriber: CatalogScmEventsServiceSubscriber): { unsubscribe: () => void; diff --git a/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.test.ts b/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.test.ts index 4adbb3b736..91a21894c8 100644 --- a/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.test.ts +++ b/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.test.ts @@ -15,11 +15,21 @@ */ import { createDeferred } from '@backstage/types'; +import { MetricsAPI } from '@opentelemetry/api'; import { DefaultCatalogScmEventsService } from './DefaultCatalogScmEventsService'; describe('DefaultCatalogScmEventsService', () => { + const counterAdd = jest.fn(); + const mockMetrics = { + getMeter: () => ({ + createCounter: () => ({ + add: counterAdd, + }), + }), + } as unknown as MetricsAPI; + it('should publish and subscribe to events', async () => { - const service = new DefaultCatalogScmEventsService(); + const service = new DefaultCatalogScmEventsService(mockMetrics); const subscriber1 = { onEvents: jest.fn(), @@ -53,7 +63,7 @@ describe('DefaultCatalogScmEventsService', () => { }); it('waits for all subscribers to acknowledge the events', async () => { - const service = new DefaultCatalogScmEventsService(); + const service = new DefaultCatalogScmEventsService(mockMetrics); const work1 = createDeferred(); const work2 = createDeferred(); @@ -102,4 +112,12 @@ describe('DefaultCatalogScmEventsService', () => { expect(completed).toBe(true); }); + + it('marks event actions taken', () => { + const service = new DefaultCatalogScmEventsService(mockMetrics); + + service.markEventActionTaken({ action: 'refresh' }); + + expect(counterAdd).toHaveBeenCalledWith(1, { action: 'refresh' }); + }); }); diff --git a/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.ts b/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.ts index 7610b7fd0a..b61878bbae 100644 --- a/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.ts +++ b/plugins/catalog-node/src/scmEvents/DefaultCatalogScmEventsService.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { Counter, MetricsAPI } from '@opentelemetry/api'; import { CatalogScmEvent, CatalogScmEventsService, @@ -21,19 +22,36 @@ import { } from './types'; /** - * The default implementation of the {@link CatalogScmEventsService}/{@link catalogScmEventsServiceRef}. + * The default implementation of the + * {@link CatalogScmEventsService}/{@link catalogScmEventsServiceRef}. * * @internal * @remarks * * This implementation is in-memory, which requires the producers and consumer * (the catalog backend) to be deployed together. + * + * It's defined in here instead of in the catalog-backend plugin because this + * allows us to have a default factory whether you happen to be co-installed + * with the catalog-backend plugin or not. */ export class DefaultCatalogScmEventsService implements CatalogScmEventsService { readonly #subscribers: Set; + readonly #metrics: { + actions: Counter<{ action: string }>; + }; - constructor() { + constructor(metrics: MetricsAPI) { this.#subscribers = new Set(); + + const meter = metrics.getMeter('default'); + this.#metrics = { + actions: meter.createCounter('catalog.events.scm.actions', { + description: + 'Number of actions taken as a result of SCM event messages', + unit: 'short', + }), + }; } subscribe(subscriber: CatalogScmEventsServiceSubscriber): { @@ -58,4 +76,8 @@ export class DefaultCatalogScmEventsService implements CatalogScmEventsService { }), ); } + + markEventActionTaken(options: { count?: number; action: string }): void { + this.#metrics.actions.add(options.count ?? 1, { action: options.action }); + } } diff --git a/plugins/catalog-node/src/scmEvents/catalogScmEventsServiceRef.ts b/plugins/catalog-node/src/scmEvents/catalogScmEventsServiceRef.ts index 1f5bc7165f..f940581ca0 100644 --- a/plugins/catalog-node/src/scmEvents/catalogScmEventsServiceRef.ts +++ b/plugins/catalog-node/src/scmEvents/catalogScmEventsServiceRef.ts @@ -18,6 +18,7 @@ import { createServiceFactory, createServiceRef, } from '@backstage/backend-plugin-api'; +import { metrics } from '@opentelemetry/api'; import { CatalogScmEventsService } from './types'; import { DefaultCatalogScmEventsService } from './DefaultCatalogScmEventsService'; @@ -39,7 +40,7 @@ export const catalogScmEventsServiceRef = service, deps: {}, createRootContext() { - return new DefaultCatalogScmEventsService(); + return new DefaultCatalogScmEventsService(metrics); }, factory(_, ctx) { return ctx; diff --git a/plugins/catalog-node/src/scmEvents/types.ts b/plugins/catalog-node/src/scmEvents/types.ts index 87cf31fc01..72161cacde 100644 --- a/plugins/catalog-node/src/scmEvents/types.ts +++ b/plugins/catalog-node/src/scmEvents/types.ts @@ -55,6 +55,26 @@ export interface CatalogScmEventsService { * guarantees. */ publish(events: CatalogScmEvent[]): Promise; + + /** + * As a consumer of SCM events, mark that you have taken an action as a result + * of an SCM event. + * + * This is typically used to record metrics or other observability signals + * about how SCM events are handled, for example counting how many refresh, + * delete, create, or move operations are triggered by incoming events. + */ + markEventActionTaken(options: { + /** + * The number of actions taken of the given type. Defaults to 1. + */ + count?: number; + /** + * The type of action taken - typically "refresh", "delete", + * "create", or "move". + */ + action: string; + }): void; } /** diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 903ce74e04..550c9616ec 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-react +## 2.0.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/frontend-test-utils@0.5.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 2.0.0 ### Minor Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 9fbd58a3b5..c383c52691 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "2.0.0", + "version": "2.0.1-next.0", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-react/report-alpha.api.md b/plugins/catalog-react/report-alpha.api.md index a514820f20..acd85b5540 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -556,9 +556,9 @@ export const EntityIconLinkBlueprint: ExtensionBlueprint<{ }>; // @alpha (undocumented) -export const EntityTableColumnTitle: ({ - translationKey, -}: EntityTableColumnTitleProps) => +export const EntityTableColumnTitle: ( + input: EntityTableColumnTitleProps, +) => | 'System' | 'Title' | 'Domain' diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index 5c3516a3a9..3a5f49f5a9 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.13 + - @backstage/plugin-devtools-react@0.1.2-next.0 + ## 0.2.26 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 3485342d4d..2efd04a781 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.2.26", + "version": "0.2.27-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index d68a9a4209..8242b7f125 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-catalog +## 1.33.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 1.33.0 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index b97267d8d4..f04e147638 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.33.0", + "version": "1.33.1-next.0", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 95fbfd9d0f..b617811885 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-config-schema +## 0.1.78-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.1.77 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index d9a16c4bb7..c643d6b1f4 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-config-schema", - "version": "0.1.77", + "version": "0.1.78-next.0", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index eedd6300de..77400b17ed 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-devtools-backend +## 0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.2.0-next.0 + - @backstage/config-loader@1.10.9-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-devtools-common@0.1.22 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 0.5.14 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 69d87c54fc..3b025b052a 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.5.14", + "version": "0.5.15-next.0", "backstage": { "role": "backend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools-react/CHANGELOG.md b/plugins/devtools-react/CHANGELOG.md index bf8751ffe8..799bbafdda 100644 --- a/plugins/devtools-react/CHANGELOG.md +++ b/plugins/devtools-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-devtools-react +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/devtools-react/package.json b/plugins/devtools-react/package.json index cf6d34b466..0b9e40187f 100644 --- a/plugins/devtools-react/package.json +++ b/plugins/devtools-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-react", - "version": "0.1.1", + "version": "0.1.2-next.0", "description": "Web library for the devtools plugin", "backstage": { "role": "web-library", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index c63d7850a3..b62339220b 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-devtools +## 0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/plugin-devtools-common@0.1.22 + - @backstage/plugin-devtools-react@0.1.2-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.1.36 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index b03eef9dcb..61160edb46 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.36", + "version": "0.1.37-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools/report.api.md b/plugins/devtools/report.api.md index 804e678e89..a74dd7eb23 100644 --- a/plugins/devtools/report.api.md +++ b/plugins/devtools/report.api.md @@ -17,7 +17,7 @@ export const ConfigContent: () => JSX_2.Element; // @public export const DevToolsLayout: { - ({ children, title, subtitle }: DevToolsLayoutProps): JSX_2.Element; + (input: DevToolsLayoutProps): JSX_2.Element; Route: (props: SubRoute) => null; }; @@ -29,7 +29,7 @@ export type DevToolsLayoutProps = { }; // @public (undocumented) -export const DevToolsPage: ({ contents }: DevToolsPageProps) => JSX_2.Element; +export const DevToolsPage: (input: DevToolsPageProps) => JSX_2.Element; // @public (undocumented) export interface DevToolsPageContent { @@ -62,9 +62,7 @@ export const ExternalDependenciesContent: () => JSX_2.Element; export const InfoContent: () => JSX_2.Element; // @public (undocumented) -export const ScheduledTaskDetailPanel: ({ - rowData, -}: { +export const ScheduledTaskDetailPanel: (input: { rowData: TaskApiTasksResponse; }) => JSX_2.Element; diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 5cd2e5eac7..2125e080b3 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.4.19 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 3e6cdb4b57..dd704866a7 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.4.19", + "version": "0.4.20-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 8191e4faca..27b8884997 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.2.28 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 5715981263..cadcc17085 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.2.28", + "version": "0.2.29-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index e83960dc3f..ec5c6f7e51 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.2.28 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index ddd6c64471..85ea3db464 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.2.28", + "version": "0.2.29-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md index 79ae4419f4..66c8523ed0 100644 --- a/plugins/events-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-server +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.1.9 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-server/package.json b/plugins/events-backend-module-bitbucket-server/package.json index 83d8d470b6..94e6c9f280 100644 --- a/plugins/events-backend-module-bitbucket-server/package.json +++ b/plugins/events-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-server", - "version": "0.1.9", + "version": "0.1.10-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index b3eb366a87..56033f47e8 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.2.28 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 7dfff9961e..9d28dc1dc6 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.2.28", + "version": "0.2.29-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index c7656fce90..99906c12cf 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-events-backend-module-github +## 0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.4.9 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index b1bb43b902..79e4bf6ec1 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.4.9", + "version": "0.4.10-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index eff3f72ec6..c81c9a244e 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.3.9 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 3ed8e2eefc..1f05d6de5a 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.3.9", + "version": "0.3.10-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-google-pubsub/CHANGELOG.md b/plugins/events-backend-module-google-pubsub/CHANGELOG.md index c3e7a19b4f..1bbf060b95 100644 --- a/plugins/events-backend-module-google-pubsub/CHANGELOG.md +++ b/plugins/events-backend-module-google-pubsub/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend-module-google-pubsub +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/filter-predicates@0.1.0 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/events-backend-module-google-pubsub/package.json b/plugins/events-backend-module-google-pubsub/package.json index b9fc748895..29ed2f230b 100644 --- a/plugins/events-backend-module-google-pubsub/package.json +++ b/plugins/events-backend-module-google-pubsub/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-google-pubsub", - "version": "0.2.0", + "version": "0.2.1-next.0", "description": "The google-pubsub backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-module-kafka/CHANGELOG.md b/plugins/events-backend-module-kafka/CHANGELOG.md index 3e1e527d48..8b601a3f3b 100644 --- a/plugins/events-backend-module-kafka/CHANGELOG.md +++ b/plugins/events-backend-module-kafka/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-kafka +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.3.1 ### Patch Changes diff --git a/plugins/events-backend-module-kafka/package.json b/plugins/events-backend-module-kafka/package.json index 2e795242cf..cb2c1fcde6 100644 --- a/plugins/events-backend-module-kafka/package.json +++ b/plugins/events-backend-module-kafka/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-kafka", - "version": "0.3.1", + "version": "0.3.2-next.0", "description": "The kafka backend module for the events plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 9bf8093c1a..4e48326968 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.1.52 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 9fefe66a44..e5ea9a9e90 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-test-utils", - "version": "0.1.52", + "version": "0.1.53-next.0", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", "backstage": { "role": "node-library", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 9b534b57c7..4a60681d58 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend +## 0.5.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.5.11 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index c4faa91b99..4642f4e92d 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.5.11", + "version": "0.5.12-next.0", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 01834edfb4..8db15b5573 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-node +## 0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.4.19 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index b7dfaa6f00..4bec93ecee 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-node", - "version": "0.4.19", + "version": "0.4.20-next.0", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 656a72b24b..2859e0ee97 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list-backend +## 1.0.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + ## 1.0.47 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index e59787ada2..f2f3d4bba9 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.47", + "version": "1.0.48-next.0", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 70f667b7bb..7a17541264 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.49-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 1.0.48 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index d671bf504a..d6065a1f9c 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.48", + "version": "1.0.49-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/gateway-backend/CHANGELOG.md b/plugins/gateway-backend/CHANGELOG.md index 9bd5f6699e..98cec7069e 100644 --- a/plugins/gateway-backend/CHANGELOG.md +++ b/plugins/gateway-backend/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-gateway-backend +## 1.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + ## 1.1.2 ### Patch Changes diff --git a/plugins/gateway-backend/package.json b/plugins/gateway-backend/package.json index 8f600ebf02..ef35c22f46 100644 --- a/plugins/gateway-backend/package.json +++ b/plugins/gateway-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gateway-backend", - "version": "1.1.2", + "version": "1.1.3-next.0", "backstage": { "role": "backend-plugin", "pluginId": "gateway", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 5817aa34cd..d80608269d 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-home-react +## 0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 0.1.35 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 419bf9b770..682beb6edd 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home-react", - "version": "0.1.35", + "version": "0.1.36-next.0", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index ecfd1ea38e..045b8737a4 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-home +## 0.9.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-compat-api@0.5.9-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-home-react@0.1.36-next.0 + ## 0.9.2 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 561ed37309..4c38991714 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.9.2", + "version": "0.9.3-next.0", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", diff --git a/plugins/home/report.api.md b/plugins/home/report.api.md index 17870ed481..a90d5755ac 100644 --- a/plugins/home/report.api.md +++ b/plugins/home/report.api.md @@ -273,11 +273,9 @@ export interface VisitDisplayContextValue { } // @public -export const VisitDisplayProvider: ({ - children, - getChipColor, - getLabel, -}: VisitDisplayProviderProps) => JSX_2.Element; +export const VisitDisplayProvider: ( + input: VisitDisplayProviderProps, +) => JSX_2.Element; // @public export interface VisitDisplayProviderProps { @@ -309,14 +307,10 @@ export type VisitInput = { }; // @public -export const VisitListener: ({ - children, - toEntityRef, - visitName, -}: { +export const VisitListener: (input: { children?: ReactNode; - toEntityRef?: ({ pathname }: { pathname: string }) => string | undefined; - visitName?: ({ pathname }: { pathname: string }) => string; + toEntityRef?: (input: { pathname: string }) => string | undefined; + visitName?: (input: { pathname: string }) => string; }) => JSX.Element; // @public @@ -389,10 +383,7 @@ export type VisitsWebStorageApiOptions = { }; // @public -export const WelcomeTitle: ({ - language, - variant, -}: WelcomeTitleLanguageProps) => JSX_2.Element; +export const WelcomeTitle: (input: WelcomeTitleLanguageProps) => JSX_2.Element; // @public (undocumented) export type WelcomeTitleLanguageProps = { diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 6d6b537cfd..4886067c19 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-kubernetes-backend +## 0.21.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-node@0.4.2-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 0.21.1 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index dc65304fb9..d773535a99 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.21.1", + "version": "0.21.2-next.0", "description": "A Backstage backend plugin that integrates towards Kubernetes", "backstage": { "role": "backend-plugin", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 94f9e3ee52..38dd2155a5 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.35-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-react@0.5.17-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.0.34 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 4455308bf4..876986e001 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-cluster", - "version": "0.0.34", + "version": "0.0.35-next.0", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index 0c8087afaf..f902343fae 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + ## 0.4.1 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index b56016e044..6b4ff1650d 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.4.1", + "version": "0.4.2-next.0", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index a1f5092472..bc698a616c 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-react +## 0.5.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-kubernetes-common@0.9.10 + ## 0.5.16 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index d4b61ef75a..abed58b6e7 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-react", - "version": "0.5.16", + "version": "0.5.17-next.0", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes-react/report.api.md b/plugins/kubernetes-react/report.api.md index 497c8673c2..bb8057b2e8 100644 --- a/plugins/kubernetes-react/report.api.md +++ b/plugins/kubernetes-react/report.api.md @@ -61,10 +61,7 @@ export class AksKubernetesAuthProvider implements KubernetesAuthProvider { } // @public -export const Cluster: ({ - clusterObjects, - podsWithErrors, -}: ClusterProps) => JSX_2.Element; +export const Cluster: (input: ClusterProps) => JSX_2.Element; // @public (undocumented) export const ClusterContext: Context; @@ -116,7 +113,9 @@ export interface ContainerScope extends PodScope { } // @public (undocumented) -export const CronJobsAccordions: ({}: CronJobsAccordionsProps) => JSX_2.Element; +export const CronJobsAccordions: ( + input: CronJobsAccordionsProps, +) => JSX_2.Element; // @public (undocumented) export type CronJobsAccordionsProps = { @@ -124,7 +123,7 @@ export type CronJobsAccordionsProps = { }; // @public (undocumented) -export const CustomResources: ({}: CustomResourcesProps) => JSX_2.Element; +export const CustomResources: (input: CustomResourcesProps) => JSX_2.Element; // @public (undocumented) export interface CustomResourcesProps { @@ -145,7 +144,7 @@ export class EksClusterLinksFormatter implements ClusterLinksFormatter { } // @public -export const ErrorList: ({ podAndErrors }: ErrorListProps) => JSX_2.Element; +export const ErrorList: (input: ErrorListProps) => JSX_2.Element; // @public export interface ErrorListProps { @@ -159,11 +158,7 @@ export type ErrorMatcher = { } & TypeMeta; // @public (undocumented) -export const ErrorPanel: ({ - entityName, - errorMessage, - clustersWithErrors, -}: ErrorPanelProps) => JSX_2.Element; +export const ErrorPanel: (input: ErrorPanelProps) => JSX_2.Element; // @public (undocumented) export type ErrorPanelProps = { @@ -174,10 +169,7 @@ export type ErrorPanelProps = { }; // @public (undocumented) -export const ErrorReporting: ({ - detectedErrors, - clusters, -}: ErrorReportingProps) => JSX_2.Element; +export const ErrorReporting: (input: ErrorReportingProps) => JSX_2.Element; // @public (undocumented) export type ErrorReportingProps = { @@ -186,18 +178,10 @@ export type ErrorReportingProps = { }; // @public -export const Events: ({ - involvedObjectName, - namespace, - clusterName, - warningEventsOnly, -}: EventsProps) => JSX_2.Element; +export const Events: (input: EventsProps) => JSX_2.Element; // @public -export const EventsContent: ({ - events, - warningEventsOnly, -}: EventsContentProps) => JSX_2.Element; +export const EventsContent: (input: EventsContentProps) => JSX_2.Element; // @public export interface EventsContentProps { @@ -297,13 +281,15 @@ export const HorizontalPodAutoscalerDrawer: (props: { }) => JSX_2.Element; // @public (undocumented) -export const IngressesAccordions: ({}: IngressesAccordionsProps) => JSX_2.Element; +export const IngressesAccordions: ( + input: IngressesAccordionsProps, +) => JSX_2.Element; // @public (undocumented) export type IngressesAccordionsProps = {}; // @public (undocumented) -export const JobsAccordions: ({ jobs }: JobsAccordionsProps) => JSX_2.Element; +export const JobsAccordions: (input: JobsAccordionsProps) => JSX_2.Element; // @public (undocumented) export type JobsAccordionsProps = { @@ -468,13 +454,7 @@ export interface KubernetesClusterLinkFormatterApi { export const kubernetesClusterLinkFormatterApiRef: ApiRef; // @public -export const KubernetesDrawer: ({ - open, - label, - drawerContentsHeader, - kubernetesObject, - children, -}: KubernetesDrawerProps) => JSX_2.Element; +export const KubernetesDrawer: (input: KubernetesDrawerProps) => JSX_2.Element; // @public (undocumented) export interface KubernetesDrawerable { @@ -549,11 +529,7 @@ export const kubernetesProxyApiRef: ApiRef; export class KubernetesProxyClient { constructor(options: { kubernetesApi: KubernetesApi }); // (undocumented) - deletePod({ - podName, - namespace, - clusterName, - }: { + deletePod(input: { podName: string; namespace: string; clusterName: string; @@ -561,23 +537,13 @@ export class KubernetesProxyClient { text: string; }>; // (undocumented) - getEventsByInvolvedObjectName({ - clusterName, - involvedObjectName, - namespace, - }: { + getEventsByInvolvedObjectName(input: { clusterName: string; involvedObjectName: string; namespace: string; }): Promise; // (undocumented) - getPodLogs({ - podName, - namespace, - clusterName, - containerName, - previous, - }: { + getPodLogs(input: { podName: string; namespace: string; clusterName: string; @@ -591,14 +557,9 @@ export class KubernetesProxyClient { // @public (undocumented) export const KubernetesStructuredMetadataTableDrawer: < T extends KubernetesDrawerable, ->({ - object, - renderObject, - kind, - buttonVariant, - expanded, - children, -}: KubernetesStructuredMetadataTableDrawerProps) => JSX_2.Element; +>( + input: KubernetesStructuredMetadataTableDrawerProps, +) => JSX_2.Element; // @public (undocumented) export interface KubernetesStructuredMetadataTableDrawerProps< @@ -619,10 +580,7 @@ export interface KubernetesStructuredMetadataTableDrawerProps< } // @public (undocumented) -export const LinkErrorPanel: ({ - cluster, - errorMessage, -}: LinkErrorPanelProps) => JSX_2.Element; +export const LinkErrorPanel: (input: LinkErrorPanelProps) => JSX_2.Element; // @public (undocumented) export type LinkErrorPanelProps = { @@ -632,7 +590,7 @@ export type LinkErrorPanelProps = { }; // @public -export const ManifestYaml: ({ object }: ManifestYamlProps) => JSX_2.Element; +export const ManifestYaml: (input: ManifestYamlProps) => JSX_2.Element; // @public export interface ManifestYamlProps { @@ -664,9 +622,9 @@ export class OpenshiftClusterLinksFormatter { } // @public -export const PendingPodContent: ({ - pod, -}: PendingPodContentProps) => JSX_2.Element; +export const PendingPodContent: ( + input: PendingPodContentProps, +) => JSX_2.Element; // @public export interface PendingPodContentProps { @@ -688,10 +646,7 @@ export interface PodAndErrors { export type PodColumns = 'READY' | 'RESOURCE'; // @public -export const PodDrawer: ({ - podAndErrors, - open, -}: PodDrawerProps) => JSX_2.Element; +export const PodDrawer: (input: PodDrawerProps) => JSX_2.Element; // @public export interface PodDrawerProps { @@ -725,9 +680,7 @@ export interface PodExecTerminalProps { export const PodLogs: FC; // @public -export const PodLogsDialog: ({ - containerScope, -}: PodLogsDialogProps) => JSX_2.Element; +export const PodLogsDialog: (input: PodLogsDialogProps) => JSX_2.Element; // @public export interface PodLogsDialogProps { @@ -776,10 +729,7 @@ export interface PodScope { } // @public (undocumented) -export const PodsTable: ({ - pods, - extraColumns, -}: PodsTablesProps) => JSX_2.Element; +export const PodsTable: (input: PodsTablesProps) => JSX_2.Element; // @public (undocumented) export type PodsTablesProps = { @@ -801,13 +751,9 @@ export const READY_COLUMNS: PodColumns; export const RESOURCE_COLUMNS: PodColumns; // @public -export const ResourceUtilization: ({ - compressed, - title, - usage, - total, - totalFormatted, -}: ResourceUtilizationProps) => JSX_2.Element; +export const ResourceUtilization: ( + input: ResourceUtilizationProps, +) => JSX_2.Element; // @public export interface ResourceUtilizationProps { @@ -836,7 +782,9 @@ export class ServerSideKubernetesAuthProvider } // @public (undocumented) -export const ServicesAccordions: ({}: ServicesAccordionsProps) => JSX_2.Element; +export const ServicesAccordions: ( + input: ServicesAccordionsProps, +) => JSX_2.Element; // @public (undocumented) export type ServicesAccordionsProps = {}; @@ -855,11 +803,7 @@ export const useCustomResources: ( ) => KubernetesObjects; // @public -export const useEvents: ({ - involvedObjectName, - namespace, - clusterName, -}: EventsOptions) => AsyncState; +export const useEvents: (input: EventsOptions) => AsyncState; // @public (undocumented) export const useKubernetesObjects: ( @@ -871,10 +815,7 @@ export const useKubernetesObjects: ( export const useMatchingErrors: (matcher: ErrorMatcher) => DetectedError[]; // @public -export const usePodLogs: ({ - containerScope, - previous, -}: PodLogsOptions) => AsyncState<{ +export const usePodLogs: (input: PodLogsOptions) => AsyncState<{ text: string; }>; diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 01779f7b6e..8e4cd54658 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kubernetes +## 0.12.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-kubernetes-common@0.9.10 + - @backstage/plugin-kubernetes-react@0.5.17-next.0 + - @backstage/plugin-permission-react@0.4.41-next.0 + ## 0.12.16 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 92e2c83244..b43665e711 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.12.16", + "version": "0.12.17-next.0", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/mcp-actions-backend/CHANGELOG.md b/plugins/mcp-actions-backend/CHANGELOG.md index 87e5def870..9cccc03c2f 100644 --- a/plugins/mcp-actions-backend/CHANGELOG.md +++ b/plugins/mcp-actions-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-mcp-actions-backend +## 0.1.10-next.0 + +### Patch Changes + +- dc81af1: Adds two new metrics to track MCP server operations and sessions. + + - `mcp.server.operation.duration`: The duration taken to process an individual MCP operation + - `mcp.server.session.duration`: The duration of the MCP session from the perspective of the server + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + ## 0.1.9 ### Patch Changes diff --git a/plugins/mcp-actions-backend/README.md b/plugins/mcp-actions-backend/README.md index c2eba60c80..095aa46122 100644 --- a/plugins/mcp-actions-backend/README.md +++ b/plugins/mcp-actions-backend/README.md @@ -75,7 +75,7 @@ export const myPlugin = createBackendPlugin({ When errors are thrown from MCP actions, the backend will handle and surface error message for any error from `@backstage/errors`. Unknown errors will be handled by `@modelcontextprotocol/sdk`'s default error handling, which may result in a generic `500 Server Error` being returned. As a result, we recommend using errors from `@backstage/errors` when applicable. -See https://backstage.io/api/stable/modules/_backstage_errors.html for a full list of supported errors. +See [Backstage Errors](https://backstage.io/docs/reference/errors/) for a full list of supported errors. When writing MCP tools, use the appropriate error from `@backstage/errors` when applicable: @@ -178,6 +178,13 @@ There's a few different ways to configure MCP tools, but here's a snippet of the } ``` +## Metrics + +The MCP Actions Backend emits metrics for the following operations: + +- `mcp.server.operation.duration`: The duration taken to process an individual MCP operation +- `mcp.server.session.duration`: The duration of the MCP session from the perspective of the server + ## Development This plugin backend can be started in a standalone mode from directly in this package with `yarn start`. It is a limited setup that is most convenient when developing the plugin backend itself. diff --git a/plugins/mcp-actions-backend/package.json b/plugins/mcp-actions-backend/package.json index 71129e8589..6d66add868 100644 --- a/plugins/mcp-actions-backend/package.json +++ b/plugins/mcp-actions-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-mcp-actions-backend", - "version": "0.1.9", + "version": "0.1.10-next.0", "backstage": { "role": "backend-plugin", "pluginId": "mcp-actions", diff --git a/plugins/mcp-actions-backend/src/metrics.ts b/plugins/mcp-actions-backend/src/metrics.ts new file mode 100644 index 0000000000..ddaa75edbd --- /dev/null +++ b/plugins/mcp-actions-backend/src/metrics.ts @@ -0,0 +1,73 @@ +/* + * Copyright 2026 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 { MetricAttributes } from '@backstage/backend-plugin-api/alpha'; + +/** + * Attributes for mcp.server.operation.duration + * Following OTel requirement levels from the spec + * + * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/#metric-mcpserveroperationduration + */ +export interface McpServerOperationAttributes extends MetricAttributes { + // Required + 'mcp.method.name': string; + + // Conditionally Required + 'error.type'?: string; + 'gen_ai.tool.name'?: string; + 'gen_ai.prompt.name'?: string; + 'mcp.resource.uri'?: string; + 'rpc.response.status_code'?: string; + + // Recommended + 'gen_ai.operation.name'?: 'execute_tool'; + 'mcp.protocol.version'?: string; + 'mcp.session.id'?: string; + 'network.transport'?: 'tcp' | 'quic' | 'pipe' | 'unix'; + 'network.protocol.name'?: string; + 'network.protocol.version'?: string; +} + +/** + * Attributes for mcp.server.session.duration + * Following OTel requirement levels from the spec + * + * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/#metric-mcpserversessionduration + */ +export interface McpServerSessionAttributes extends MetricAttributes { + // Conditionally Required + 'error.type'?: string; + + // Recommended + 'mcp.protocol.version'?: string; + 'network.transport'?: 'tcp' | 'quic' | 'pipe' | 'unix'; + 'network.protocol.name'?: string; + 'network.protocol.version'?: string; +} + +/** + * OTel recommended bucket boundaries for MCP metrics + * + * @remarks + * + * Based on the MCP metrics defined in the OTel semantic conventions v1.39.0 + * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/ + * + */ +export const bucketBoundaries = [ + 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300, +]; diff --git a/plugins/mcp-actions-backend/src/plugin.test.ts b/plugins/mcp-actions-backend/src/plugin.test.ts index 0bbe5d5340..1e3297792a 100644 --- a/plugins/mcp-actions-backend/src/plugin.test.ts +++ b/plugins/mcp-actions-backend/src/plugin.test.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { metricsServiceMock } from '@backstage/backend-test-utils/alpha'; import { mcpPlugin } from './plugin'; import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; import { createBackendPlugin } from '@backstage/backend-plugin-api'; @@ -52,6 +53,7 @@ describe('Mcp Backend', () => { features: [ mcpPlugin, mockPluginWithActions, + metricsServiceMock.mock().factory, mockServices.rootConfig.factory({ data: { backend: { diff --git a/plugins/mcp-actions-backend/src/plugin.ts b/plugins/mcp-actions-backend/src/plugin.ts index 34a9501fed..71a40db18d 100644 --- a/plugins/mcp-actions-backend/src/plugin.ts +++ b/plugins/mcp-actions-backend/src/plugin.ts @@ -25,6 +25,7 @@ import { createSseRouter } from './routers/createSseRouter'; import { actionsRegistryServiceRef, actionsServiceRef, + metricsServiceRef, } from '@backstage/backend-plugin-api/alpha'; /** @@ -46,6 +47,7 @@ export const mcpPlugin = createBackendPlugin({ rootRouter: coreServices.rootHttpRouter, discovery: coreServices.discovery, config: coreServices.rootConfig, + metrics: metricsServiceRef, }, async init({ actions, @@ -55,9 +57,11 @@ export const mcpPlugin = createBackendPlugin({ rootRouter, discovery, config, + metrics, }) { const mcpService = await McpService.create({ actions, + metrics, }); const sseRouter = createSseRouter({ @@ -69,6 +73,7 @@ export const mcpPlugin = createBackendPlugin({ mcpService, httpAuth, logger, + metrics, }); const router = Router(); diff --git a/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts b/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts index 9d6fd1840b..b08605337d 100644 --- a/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts +++ b/plugins/mcp-actions-backend/src/routers/createStreamableRouter.ts @@ -15,23 +15,47 @@ */ import PromiseRouter from 'express-promise-router'; import { Router } from 'express'; +import { performance } from 'node:perf_hooks'; import { McpService } from '../services/McpService'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js'; import { HttpAuthService, LoggerService } from '@backstage/backend-plugin-api'; import { isError } from '@backstage/errors'; +import { MetricsService } from '@backstage/backend-plugin-api/alpha'; +import { bucketBoundaries, McpServerSessionAttributes } from '../metrics'; export const createStreamableRouter = ({ mcpService, httpAuth, logger, + metrics, }: { mcpService: McpService; logger: LoggerService; httpAuth: HttpAuthService; + metrics: MetricsService; }): Router => { const router = PromiseRouter(); + const sessionDuration = metrics.createHistogram( + 'mcp.server.session.duration', + { + description: + 'The duration of the MCP session as observed on the MCP server', + unit: 's', + advice: { explicitBucketBoundaries: bucketBoundaries }, + }, + ); + router.post('/', async (req, res) => { + const sessionStart = performance.now(); + + const baseAttributes: McpServerSessionAttributes = { + 'mcp.protocol.version': LATEST_PROTOCOL_VERSION, + 'network.transport': 'tcp', + 'network.protocol.name': 'http', + }; + try { const server = mcpService.getServer({ credentials: await httpAuth.credentials(req), @@ -49,8 +73,14 @@ export const createStreamableRouter = ({ res.on('close', () => { transport.close(); server.close(); + + const durationSeconds = (performance.now() - sessionStart) / 1000; + + sessionDuration.record(durationSeconds, baseAttributes); }); } catch (error) { + const errorType = isError(error) ? error.name : 'Error'; + if (isError(error)) { logger.error(error.message); } @@ -65,6 +95,13 @@ export const createStreamableRouter = ({ id: null, }); } + + const durationSeconds = (performance.now() - sessionStart) / 1000; + + sessionDuration.record(durationSeconds, { + ...baseAttributes, + 'error.type': errorType, + }); } }); diff --git a/plugins/mcp-actions-backend/src/services/McpService.test.ts b/plugins/mcp-actions-backend/src/services/McpService.test.ts index cd1c98f5b1..038700c4a5 100644 --- a/plugins/mcp-actions-backend/src/services/McpService.test.ts +++ b/plugins/mcp-actions-backend/src/services/McpService.test.ts @@ -16,7 +16,10 @@ import { mockCredentials } from '@backstage/backend-test-utils'; import { McpService } from './McpService'; -import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha'; +import { + actionsRegistryServiceMock, + metricsServiceMock, +} from '@backstage/backend-test-utils/alpha'; import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { @@ -38,8 +41,10 @@ describe('McpService', () => { action: async () => ({ output: { output: 'test' } }), }); + const mockMetrics = metricsServiceMock.mock(); const mcpService = await McpService.create({ actions: mockActionsRegistry, + metrics: mockMetrics, }); const server = mcpService.getServer({ @@ -90,6 +95,60 @@ describe('McpService', () => { name: 'mock-action', }, ]); + + const histogram = mockMetrics.createHistogram.mock.results[0]?.value; + expect(histogram.record).toHaveBeenCalledTimes(1); + expect(histogram.record).toHaveBeenCalledWith( + expect.any(Number), + expect.objectContaining({ + 'mcp.method.name': 'tools/list', + }), + ); + expect(histogram.record.mock.calls[0][1]).not.toHaveProperty('error.type'); + }); + + it('should record metrics with error.type when tools/list fails', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + mockActionsRegistry.list = jest + .fn() + .mockRejectedValue(new Error('List failed')); + + const mockMetrics = metricsServiceMock.mock(); + const mcpService = await McpService.create({ + actions: mockActionsRegistry, + metrics: mockMetrics, + }); + + const server = mcpService.getServer({ + credentials: mockCredentials.user(), + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + await expect( + client.request({ method: 'tools/list' }, ListToolsResultSchema), + ).rejects.toThrow(); + + const histogram = mockMetrics.createHistogram.mock.results[0]?.value; + expect(histogram.record).toHaveBeenCalledTimes(1); + expect(histogram.record).toHaveBeenCalledWith( + expect.any(Number), + expect.objectContaining({ + 'mcp.method.name': 'tools/list', + 'error.type': 'Error', + }), + ); }); it('should call the action when the tool is invoked', async () => { @@ -107,8 +166,10 @@ describe('McpService', () => { action: mockAction, }); + const mockMetrics = metricsServiceMock.mock(); const mcpService = await McpService.create({ actions: mockActionsRegistry, + metrics: mockMetrics, }); const server = mcpService.getServer({ @@ -154,11 +215,25 @@ describe('McpService', () => { ].join('\n'), }, ]); + + const histogram = mockMetrics.createHistogram.mock.results[0]?.value; + expect(histogram.record).toHaveBeenCalledTimes(1); + expect(histogram.record).toHaveBeenCalledWith( + expect.any(Number), + expect.objectContaining({ + 'mcp.method.name': 'tools/call', + 'gen_ai.tool.name': 'mock-action', + 'gen_ai.operation.name': 'execute_tool', + }), + ); + expect(histogram.record.mock.calls[0][1]).not.toHaveProperty('error.type'); }); it('should return an error when the action is not found', async () => { + const mockMetrics = metricsServiceMock.mock(); const mcpService = await McpService.create({ actions: actionsRegistryServiceMock(), + metrics: mockMetrics, }); const server = mcpService.getServer({ @@ -194,5 +269,78 @@ describe('McpService', () => { ], isError: true, }); + + const histogram = mockMetrics.createHistogram.mock.results[0]?.value; + expect(histogram.record).toHaveBeenCalledTimes(1); + expect(histogram.record).toHaveBeenCalledWith( + expect.any(Number), + expect.objectContaining({ + 'mcp.method.name': 'tools/call', + 'gen_ai.tool.name': 'mock-action', + 'gen_ai.operation.name': 'execute_tool', + 'error.type': 'tool_error', + }), + ); + }); + + it('should record metrics with error.type when tool invocation throws', async () => { + const mockActionsRegistry = actionsRegistryServiceMock(); + const customError = new Error('Action failed'); + customError.name = 'CustomError'; + mockActionsRegistry.register({ + name: 'failing-action', + title: 'Failing', + description: 'Fails', + schema: { + input: z => z.object({}), + output: z => z.object({}), + }, + action: jest.fn().mockRejectedValue(customError), + }); + + const mockMetrics = metricsServiceMock.mock(); + const mcpService = await McpService.create({ + actions: mockActionsRegistry, + metrics: mockMetrics, + }); + + const server = mcpService.getServer({ + credentials: mockCredentials.user(), + }); + + const client = new Client({ + name: 'test client', + version: '1.0', + }); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + await expect( + client.request( + { + method: 'tools/call', + params: { name: 'failing-action', arguments: {} }, + }, + CallToolResultSchema, + ), + ).rejects.toThrow('Action failed'); + + const histogram = mockMetrics.createHistogram.mock.results[0]?.value; + expect(histogram.record).toHaveBeenCalledTimes(1); + expect(histogram.record).toHaveBeenCalledWith( + expect.any(Number), + expect.objectContaining({ + 'mcp.method.name': 'tools/call', + 'gen_ai.tool.name': 'failing-action', + 'gen_ai.operation.name': 'execute_tool', + 'error.type': 'CustomError', + }), + ); }); }); diff --git a/plugins/mcp-actions-backend/src/services/McpService.ts b/plugins/mcp-actions-backend/src/services/McpService.ts index c6cdf901d7..b6338a0e1d 100644 --- a/plugins/mcp-actions-backend/src/services/McpService.ts +++ b/plugins/mcp-actions-backend/src/services/McpService.ts @@ -20,21 +20,43 @@ import { CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { JsonObject } from '@backstage/types'; -import { ActionsService } from '@backstage/backend-plugin-api/alpha'; +import { + ActionsService, + MetricsServiceHistogram, + MetricsService, +} from '@backstage/backend-plugin-api/alpha'; import { version } from '@backstage/plugin-mcp-actions-backend/package.json'; import { NotFoundError } from '@backstage/errors'; +import { performance } from 'node:perf_hooks'; import { handleErrors } from './handleErrors'; +import { bucketBoundaries, McpServerOperationAttributes } from '../metrics'; export class McpService { private readonly actions: ActionsService; + private readonly operationDuration: MetricsServiceHistogram; - constructor(actions: ActionsService) { + constructor(actions: ActionsService, metrics: MetricsService) { this.actions = actions; + this.operationDuration = + metrics.createHistogram( + 'mcp.server.operation.duration', + { + description: 'MCP request duration as observed on the receiver', + unit: 's', + advice: { explicitBucketBoundaries: bucketBoundaries }, + }, + ); } - static async create({ actions }: { actions: ActionsService }) { - return new McpService(actions); + static async create({ + actions, + metrics, + }: { + actions: ActionsService; + metrics: MetricsService; + }) { + return new McpService(actions, metrics); } getServer({ credentials }: { credentials: BackstageCredentials }) { @@ -48,57 +70,101 @@ export class McpService { ); server.setRequestHandler(ListToolsRequestSchema, async () => { - // TODO: switch this to be configuration based later - const { actions } = await this.actions.list({ credentials }); + const startTime = performance.now(); + let errorType: string | undefined; - return { - tools: actions.map(action => ({ - inputSchema: action.schema.input, - // todo(blam): this is unfortunately not supported by most clients yet. - // When this is provided you need to provide structuredContent instead. - // outputSchema: action.schema.output, - name: action.name, - description: action.description, - annotations: { - title: action.title, - destructiveHint: action.attributes.destructive, - idempotentHint: action.attributes.idempotent, - readOnlyHint: action.attributes.readOnly, - openWorldHint: false, - }, - })), - }; + try { + // TODO: switch this to be configuration based later + const { actions } = await this.actions.list({ credentials }); + + return { + tools: actions.map(action => ({ + inputSchema: action.schema.input, + // todo(blam): this is unfortunately not supported by most clients yet. + // When this is provided you need to provide structuredContent instead. + // outputSchema: action.schema.output, + name: action.name, + description: action.description, + annotations: { + title: action.title, + destructiveHint: action.attributes.destructive, + idempotentHint: action.attributes.idempotent, + readOnlyHint: action.attributes.readOnly, + openWorldHint: false, + }, + })), + }; + } catch (err) { + errorType = err instanceof Error ? err.name : 'Error'; + throw err; + } finally { + const durationSeconds = (performance.now() - startTime) / 1000; + + this.operationDuration.record(durationSeconds, { + 'mcp.method.name': 'tools/list', + ...(errorType && { 'error.type': errorType }), + }); + } }); server.setRequestHandler(CallToolRequestSchema, async ({ params }) => { - return handleErrors(async () => { - const { actions } = await this.actions.list({ credentials }); - const action = actions.find(a => a.name === params.name); + const startTime = performance.now(); + let errorType: string | undefined; + let isError = false; - if (!action) { - throw new NotFoundError(`Action "${params.name}" not found`); - } + try { + const result = await handleErrors(async () => { + const { actions } = await this.actions.list({ credentials }); + const action = actions.find(a => a.name === params.name); - const { output } = await this.actions.invoke({ - id: action.id, - input: params.arguments as JsonObject, - credentials, + if (!action) { + throw new NotFoundError(`Action "${params.name}" not found`); + } + + const { output } = await this.actions.invoke({ + id: action.id, + input: params.arguments as JsonObject, + credentials, + }); + + return { + // todo(blam): unfortunately structuredContent is not supported by most clients yet. + // so the validation for the output happens in the default actions registry + // and we return it as json text instead for now. + content: [ + { + type: 'text', + text: ['```json', JSON.stringify(output, null, 2), '```'].join( + '\n', + ), + }, + ], + }; }); - return { - // todo(blam): unfortunately structuredContent is not supported by most clients yet. - // so the validation for the output happens in the default actions registry - // and we return it as json text instead for now. - content: [ - { - type: 'text', - text: ['```json', JSON.stringify(output, null, 2), '```'].join( - '\n', - ), - }, - ], - }; - }); + isError = !!(result as { isError?: boolean })?.isError; + return result; + } catch (err) { + errorType = err instanceof Error ? err.name : 'Error'; + throw err; + } finally { + const durationSeconds = (performance.now() - startTime) / 1000; + + // Determine error.type per OTel MCP spec: + // - Thrown exceptions use the error name + // - CallToolResult with isError=true uses 'tool_error' + let errorAttribute: string | undefined = errorType; + if (!errorAttribute && isError) { + errorAttribute = 'tool_error'; + } + + this.operationDuration.record(durationSeconds, { + 'mcp.method.name': 'tools/call', + 'gen_ai.tool.name': params.name, + 'gen_ai.operation.name': 'execute_tool', + ...(errorAttribute && { 'error.type': errorAttribute }), + }); + } }); return server; diff --git a/plugins/mui-to-bui/CHANGELOG.md b/plugins/mui-to-bui/CHANGELOG.md index ad24084330..6164b75fd5 100644 --- a/plugins/mui-to-bui/CHANGELOG.md +++ b/plugins/mui-to-bui/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-mui-to-bui +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/ui@0.12.1-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + ## 0.2.4 ### Patch Changes diff --git a/plugins/mui-to-bui/package.json b/plugins/mui-to-bui/package.json index de5334e46c..c9d563aa94 100644 --- a/plugins/mui-to-bui/package.json +++ b/plugins/mui-to-bui/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-mui-to-bui", - "version": "0.2.4", + "version": "0.2.5-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "mui-to-bui", diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 8032c0448a..d39ec31c88 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/integration-aws-node@0.1.20 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + ## 0.3.18 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index cf57cf11bd..515cbe6409 100644 --- a/plugins/notifications-backend-module-email/package.json +++ b/plugins/notifications-backend-module-email/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-email", - "version": "0.3.18", + "version": "0.3.19-next.0", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-slack/CHANGELOG.md b/plugins/notifications-backend-module-slack/CHANGELOG.md index 39894a62fb..19ab1967ef 100644 --- a/plugins/notifications-backend-module-slack/CHANGELOG.md +++ b/plugins/notifications-backend-module-slack/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-notifications-backend-module-slack +## 0.4.0-next.0 + +### Minor Changes + +- 749ba60: Add an extension for custom Slack message layouts + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + ## 0.3.1 ### Patch Changes diff --git a/plugins/notifications-backend-module-slack/package.json b/plugins/notifications-backend-module-slack/package.json index 66a9fe6d6f..f8ced6fce5 100644 --- a/plugins/notifications-backend-module-slack/package.json +++ b/plugins/notifications-backend-module-slack/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend-module-slack", - "version": "0.3.1", + "version": "0.4.0-next.0", "description": "The slack backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index 683d823808..903420657e 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-backend +## 0.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + ## 0.6.2 ### Patch Changes diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index be863ed61f..0aebccc5de 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.6.2", + "version": "0.6.3-next.0", "backstage": { "role": "backend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications-node/CHANGELOG.md b/plugins/notifications-node/CHANGELOG.md index db2f7c5329..1b569a1493 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-notifications-node +## 0.2.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-signals-node@0.1.29-next.0 + ## 0.2.23 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index b1cc1ad49f..87f62a7e3b 100644 --- a/plugins/notifications-node/package.json +++ b/plugins/notifications-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-node", - "version": "0.2.23", + "version": "0.2.24-next.0", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 49b4f3b174..b838b58087 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-notifications +## 0.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-signals-react@0.0.20-next.0 + ## 0.5.14 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 37beefdab5..891b7f38bc 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.5.14", + "version": "0.5.15-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications/report.api.md b/plugins/notifications/report.api.md index 8a1fd47bad..2c056d4e91 100644 --- a/plugins/notifications/report.api.md +++ b/plugins/notifications/report.api.md @@ -169,20 +169,9 @@ export type NotificationsSideBarItemProps = { }; // @public (undocumented) -export const NotificationsTable: ({ - title, - markAsReadOnLinkOpen, - isLoading, - notifications, - isUnread, - onUpdate, - setContainsText, - onPageChange, - onRowsPerPageChange, - page, - pageSize, - totalCount, -}: NotificationsTableProps) => JSX_2.Element; +export const NotificationsTable: ( + input: NotificationsTableProps, +) => JSX_2.Element; // @public (undocumented) export type NotificationsTableProps = Pick< diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index d8963590c5..3f468b6339 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org-react +## 0.1.48-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + ## 0.1.47 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index d96e1b9efe..cc51eb5c1c 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.47", + "version": "0.1.48-next.0", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index ecdcefeaa5..a77e649b38 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org +## 0.6.50-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-catalog-common@1.1.8 + ## 0.6.49 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 9de7bf3536..62a4c9fd1b 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.49", + "version": "0.6.50-next.0", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index a097f7e4ac..90291ecb49 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 0.2.16 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 01cd3cb2e8..9038d05635 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", - "version": "0.2.16", + "version": "0.2.17-next.0", "description": "Allow all policy backend module for the permission plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 3d4730cfbd..53754d5674 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-backend +## 0.7.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + ## 0.7.9 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 9d1bbcfe1f..9a79b28680 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.7.9", + "version": "0.7.10-next.0", "backstage": { "role": "backend-plugin", "pluginId": "permission", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 4a6d9f7086..6105e5af1d 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-node +## 0.10.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-permission-common@0.9.6 + ## 0.10.10 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index b9b992cb14..2d9372559b 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.10.10", + "version": "0.10.11-next.0", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 5ffd696728..ccdb6b5e22 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.4.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.6 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/plugin-permission-common@0.9.6 + ## 0.4.40 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 3c62e2c853..eb98150e64 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.40", + "version": "0.4.41-next.0", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index c8d4e78489..c98b874891 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.6.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-proxy-node@0.1.13-next.0 + ## 0.6.10 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index f813c858d4..e1485befc7 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.6.10", + "version": "0.6.11-next.0", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", diff --git a/plugins/proxy-node/CHANGELOG.md b/plugins/proxy-node/CHANGELOG.md index 0a88dfc7fe..e27731f61c 100644 --- a/plugins/proxy-node/CHANGELOG.md +++ b/plugins/proxy-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-proxy-node +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + ## 0.1.12 ### Patch Changes diff --git a/plugins/proxy-node/package.json b/plugins/proxy-node/package.json index 378af6e3ff..e3da75c78c 100644 --- a/plugins/proxy-node/package.json +++ b/plugins/proxy-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-node", - "version": "0.1.12", + "version": "0.1.13-next.0", "description": "The plugin-proxy-node module for @backstage/plugin-proxy-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index 69bf4716e1..27b6f2e934 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 2c88b0d1e3..a5735fa15c 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The azure module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md index b707fd65eb..ee15ba6f59 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-bitbucket-cloud-common@0.3.8-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index a1701d704f..c57240f97b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud", - "version": "0.3.3", + "version": "0.3.4-next.0", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 1cd3c24adc..cba6cdc118 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index 38881b8d44..6b813c33cf 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/package.json +++ b/plugins/scaffolder-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket-server", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 7fe5027422..286dcbece7 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.3.4-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.19-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.19 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 31ef4d0a94..d048f9dcc9 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", - "version": "0.3.19", + "version": "0.3.20-next.0", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 7d935f288c..585925ca27 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index 37494f321e..69bcd089c0 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", - "version": "0.3.18", + "version": "0.3.19-next.0", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index aae0ad9a09..55d0e78017 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.15.3-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.20 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 85d9b6a61f..b1cb303441 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", - "version": "0.3.20", + "version": "0.3.21-next.0", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md index 558c8af8a3..bf9c2606fe 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 2a30a03b54..f2c354feaf 100644 --- a/plugins/scaffolder-backend-module-gcp/package.json +++ b/plugins/scaffolder-backend-module-gcp/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gcp", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The GCP Bucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index f0ca02b932..c300740667 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 91fb27faad..d16e7fdc29 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index d9a2504e73..c8d640494f 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 28c565b481..693e9560f2 100644 --- a/plugins/scaffolder-backend-module-gitea/package.json +++ b/plugins/scaffolder-backend-module-gitea/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitea", - "version": "0.2.18", + "version": "0.2.19-next.0", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index ae8efce7ad..567787aeb7 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.9.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.9.6 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index f1b8bd053d..1b599c8558 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", - "version": "0.9.6", + "version": "0.9.7-next.0", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 9062c4316a..c6a07bd53a 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.11.4-next.0 + +### Patch Changes + +- 5730c8e: Added `maskedAndHidden` option to `gitlab:projectVariable:create` and `publish:gitlab` action to support creating GitLab project variables that are both masked and hidden. Updated gitbeaker to version 43.8.0 for proper type support. +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.11.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index a4e123682e..558de71045 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.11.3", + "version": "0.11.4-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index 37ee4d20db..84c719266e 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/plugin-notifications-common@0.2.1 + - @backstage/plugin-notifications-node@0.2.24-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index b364d93ef7..5dd0a94d32 100644 --- a/plugins/scaffolder-backend-module-notifications/package.json +++ b/plugins/scaffolder-backend-module-notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-notifications", - "version": "0.1.19", + "version": "0.1.20-next.0", "description": "The notifications backend module for the scaffolder plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 5b7036235b..e7590507a9 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.5.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 0ec751cde4..73b18d7daa 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", - "version": "0.5.18", + "version": "0.5.19-next.0", "description": "A module for the scaffolder backend that lets you template projects using Rails", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 4f53ef6710..b42cf8bb61 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index d084c92eb6..96484013a8 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.3.1", + "version": "0.3.2-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index 89b05fc273..7f5bf1a9a2 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + - @backstage/plugin-scaffolder-node-test-utils@0.3.9-next.0 + ## 0.4.19 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 4302bfb29c..8b41d9a053 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.4.19", + "version": "0.4.20-next.0", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index e3e87f80ff..460664fc2e 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-scaffolder-backend +## 3.1.4-next.0 + +### Patch Changes + +- 4e39e63: Removed unused dependencies +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 3.1.3 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index d26941076a..64e8ce29e7 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "3.1.3", + "version": "3.1.4-next.0", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 66a2dc78fc..80bc88bbe5 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-common +## 1.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + ## 1.7.6 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 55ca47472e..98520a4381 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.7.6", + "version": "1.7.7-next.0", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/scaffolder-common/report.api.md b/plugins/scaffolder-common/report.api.md index c6c5141cf2..02df01397c 100644 --- a/plugins/scaffolder-common/report.api.md +++ b/plugins/scaffolder-common/report.api.md @@ -149,12 +149,7 @@ export class ScaffolderClient implements ScaffolderApi { scmIntegrationsApi: ScmIntegrationRegistry; useLongPollingLogs?: boolean; }); - autocomplete({ - token, - resource, - provider, - context, - }: { + autocomplete(input: { token: string; provider: string; resource: string; diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index 95204f458e..1f93005bfe 100644 --- a/plugins/scaffolder-node-test-utils/CHANGELOG.md +++ b/plugins/scaffolder-node-test-utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-node-test-utils +## 0.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-test-utils@1.11.1-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-scaffolder-node@0.12.6-next.0 + ## 0.3.8 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index f9eb2af520..57686d0b6a 100644 --- a/plugins/scaffolder-node-test-utils/package.json +++ b/plugins/scaffolder-node-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node-test-utils", - "version": "0.3.8", + "version": "0.3.9-next.0", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index ca84b88546..506640c822 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.12.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + ## 0.12.5 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 1c3147ab2f..44924831cb 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.12.5", + "version": "0.12.6-next.0", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index e1d49f571a..3a01b7f788 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -11,11 +11,7 @@ import { TemplateGlobal as TemplateGlobal_2 } from '@backstage/plugin-scaffolder import { z } from 'zod'; // @alpha -export type AutocompleteHandler = ({ - resource, - token, - context, -}: { +export type AutocompleteHandler = (input: { resource: string; token: string; context: Record; @@ -125,10 +121,7 @@ export const restoreWorkspace: (opts: { // @alpha export interface ScaffolderAutocompleteExtensionPoint { // (undocumented) - addAutocompleteProvider({ - id, - handler, - }: { + addAutocompleteProvider(input: { id: string; handler: AutocompleteHandler; }): void; @@ -217,13 +210,7 @@ export interface WorkspaceProvider { targetPath: string; }): Promise; // (undocumented) - serializeWorkspace({ - path, - taskId, - }: { - path: string; - taskId: string; - }): Promise; + serializeWorkspace(input: { path: string; taskId: string }): Promise; } // @alpha (undocumented) diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index c8dc8208fa..56e46e55ac 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-scaffolder-react +## 1.19.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + ## 1.19.7 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index ad95d45ace..8738088664 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.19.7", + "version": "1.19.8-next.0", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 3fcd488f9a..c321001bd3 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder +## 1.35.5-next.0 + +### Patch Changes + +- bd5b842: Added a new `ui:autoSelect` option to the EntityPicker field that controls whether an entity is automatically selected when the field loses focus. When set to `false`, the field will remain empty if the user closes it without explicitly selecting an entity, preventing unintentional selections. Defaults to `true` for backward compatibility. +- ee87720: Added back the `formFieldsApiRef` and `ScaffolderFormFieldsApi` alpha exports that were unintentionally removed. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/types@1.2.2 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-react@0.4.41-next.0 + - @backstage/plugin-scaffolder-common@1.7.7-next.0 + - @backstage/plugin-scaffolder-react@1.19.8-next.0 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 1.35.3 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index b69cea955b..a36b5016e4 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.35.3", + "version": "1.35.5-next.0", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 943b139cb9..e553e706da 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -480,6 +480,9 @@ export const formDecoratorsApi: OverridableExtensionDefinition<{ // @alpha (undocumented) export const formDecoratorsApiRef: ApiRef; +// @alpha (undocumented) +export const formFieldsApiRef: ApiRef; + // @alpha @deprecated export type FormProps = Pick< FormProps_2, @@ -499,6 +502,12 @@ export interface ScaffolderFormDecoratorsApi { getFormDecorators(): Promise; } +// @alpha (undocumented) +export interface ScaffolderFormFieldsApi { + // (undocumented) + loadFormFields(): Promise; +} + // @public (undocumented) export type ScaffolderTemplateEditorClassKey = | 'root' diff --git a/plugins/scaffolder/src/alpha/formFieldsApi.ts b/plugins/scaffolder/src/alpha/formFieldsApi.ts index df88645eb4..bcc2190f7e 100644 --- a/plugins/scaffolder/src/alpha/formFieldsApi.ts +++ b/plugins/scaffolder/src/alpha/formFieldsApi.ts @@ -19,17 +19,18 @@ import { createApiRef, createExtensionInput, } from '@backstage/frontend-plugin-api'; -import { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha'; +import { + FormFieldBlueprint, + type FormField, +} from '@backstage/plugin-scaffolder-react/alpha'; import { OpaqueFormField } from '@internal/scaffolder'; -interface FormField { - readonly $$type: '@backstage/scaffolder/FormField'; -} - -interface ScaffolderFormFieldsApi { +/** @alpha */ +export interface ScaffolderFormFieldsApi { loadFormFields(): Promise; } +/** @alpha */ const formFieldsApiRef = createApiRef({ id: 'plugin.scaffolder.form-fields-loader', }); diff --git a/plugins/scaffolder/src/alpha/index.ts b/plugins/scaffolder/src/alpha/index.ts index 53e2b8f0bf..a0b30fd3df 100644 --- a/plugins/scaffolder/src/alpha/index.ts +++ b/plugins/scaffolder/src/alpha/index.ts @@ -24,5 +24,9 @@ export { export { scaffolderTranslationRef } from '../translation'; export * from './api'; +export { + formFieldsApiRef, + type ScaffolderFormFieldsApi, +} from './formFieldsApi'; export { default } from './plugin'; diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 8fb7cf396c..eb5fcd9b28 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search-backend-module-catalog +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 0.3.12 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 8e3a58a003..d6b3318020 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-catalog", - "version": "0.3.12", + "version": "0.3.13-next.0", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index a5db94bfb0..fa550ad601 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.8.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 1.8.0 ### Minor Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 6cbd4133a5..0f64dda6a9 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", - "version": "1.8.0", + "version": "1.8.1-next.0", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 1d8db5cf83..501a052f05 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-explore +## 0.3.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 0.3.11 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 6a2c89e334..5185962af0 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-explore", - "version": "0.3.11", + "version": "0.3.12-next.0", "description": "A module for the search backend that exports explore modules", "backstage": { "moved": "@backstage-community/plugin-search-backend-module-explore", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index de608e769e..f76197bf7f 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 0.5.52 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 74688066e1..28ad927826 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-pg", - "version": "0.5.52", + "version": "0.5.53-next.0", "description": "A module for the search backend that implements search using PostgreSQL", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index 89061fca05..60a6719132 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.3.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 0.3.17 ### Patch Changes diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json index 8500b396f5..c5c8ba0218 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", - "version": "0.3.17", + "version": "0.3.18-next.0", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index dc4aac2f8a..b445ae0477 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/plugin-catalog-common@1.1.8 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + ## 0.4.11 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index a9e845030c..b85abc2715 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", - "version": "0.4.11", + "version": "0.4.12-next.0", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 35bb537506..ba1c8f1197 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-node +## 1.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-search-common@1.2.22 + ## 1.4.1 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 4d80beabb9..32bfd43019 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend-node", - "version": "1.4.1", + "version": "1.4.2-next.0", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 36d4330543..0b18e1ccce 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-search-backend +## 2.0.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/backend-openapi-utils@0.6.7-next.0 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-permission-common@0.9.6 + - @backstage/plugin-permission-node@0.10.11-next.0 + - @backstage/plugin-search-backend-node@1.4.2-next.0 + - @backstage/plugin-search-common@1.2.22 + ## 2.0.12 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 28070714b5..4c4739e967 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "2.0.12", + "version": "2.0.13-next.0", "description": "The Backstage backend plugin that provides your backstage app with search", "backstage": { "role": "backend-plugin", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index e9668c0f6a..53739b9a14 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-react +## 1.10.5-next.0 + +### Patch Changes + +- d5eb954: Fixes the search component not registering the first search on navigate to the search page. +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-search-common@1.2.22 + ## 1.10.3 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 76b575b5c9..b7a5a99bff 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.10.3", + "version": "1.10.5-next.0", "backstage": { "role": "web-library", "pluginId": "search", diff --git a/plugins/search-react/src/context/SearchContext.tsx b/plugins/search-react/src/context/SearchContext.tsx index dc129c6327..0d18b888e5 100644 --- a/plugins/search-react/src/context/SearchContext.tsx +++ b/plugins/search-react/src/context/SearchContext.tsx @@ -138,14 +138,13 @@ const useSearchContextValue = ( const result = useAsync(async (): Promise => { if (isFirstEmptyMount.current) { + isFirstEmptyMount.current = false; if (!term && !types.length && !Object.keys(filters).length) { return { results: [], numberOfResults: 0, }; } - - isFirstEmptyMount.current = false; } // Here we cancel the previous request before making a new one diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 67d6d87ed6..93711e086f 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search +## 1.6.2-next.0 + +### Patch Changes + +- d5eb954: Fixes the search component not registering the first search on navigate to the search page. +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-search-common@1.2.22 + ## 1.6.0 ### Minor Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 0ab2bd3511..e65a07c145 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.6.0", + "version": "1.6.2-next.0", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search/src/components/SearchPage/SearchPage.tsx b/plugins/search/src/components/SearchPage/SearchPage.tsx index 8428fb6bb5..92b327207f 100644 --- a/plugins/search/src/components/SearchPage/SearchPage.tsx +++ b/plugins/search/src/components/SearchPage/SearchPage.tsx @@ -59,9 +59,7 @@ export const UrlUpdater = () => { setPageCursor(query.pageCursor as string); } - if (query.types) { - setTypes(query.types as string[]); - } + setTypes(query.types ? (query.types as string[]) : []); }, [prevQueryParams, location, setTerm, setTypes, setPageCursor, setFilters]); useEffect(() => { diff --git a/plugins/signals-backend/CHANGELOG.md b/plugins/signals-backend/CHANGELOG.md index 9ab368e27d..a9a76f761f 100644 --- a/plugins/signals-backend/CHANGELOG.md +++ b/plugins/signals-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals-backend +## 0.3.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-events-node@0.4.20-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + ## 0.3.12 ### Patch Changes diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index 456607f2ea..df7ef8c99f 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-backend", - "version": "0.3.12", + "version": "0.3.13-next.0", "backstage": { "role": "backend-plugin", "pluginId": "signals", diff --git a/plugins/signals-node/CHANGELOG.md b/plugins/signals-node/CHANGELOG.md index 94b0a03575..cc28371c6a 100644 --- a/plugins/signals-node/CHANGELOG.md +++ b/plugins/signals-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-signals-node +## 0.1.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/config@1.3.6 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-events-node@0.4.20-next.0 + ## 0.1.28 ### Patch Changes diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 7453a7ed0f..ee254ef5e8 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-node", - "version": "0.1.28", + "version": "0.1.29-next.0", "description": "Node.js library for the signals plugin", "backstage": { "role": "node-library", diff --git a/plugins/signals-react/CHANGELOG.md b/plugins/signals-react/CHANGELOG.md index 8509cc043d..c21647cc29 100644 --- a/plugins/signals-react/CHANGELOG.md +++ b/plugins/signals-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-signals-react +## 0.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/types@1.2.2 + ## 0.0.19 ### Patch Changes diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json index a24132d283..12723e0bf3 100644 --- a/plugins/signals-react/package.json +++ b/plugins/signals-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals-react", - "version": "0.0.19", + "version": "0.0.20-next.0", "description": "Web library for the signals plugin", "backstage": { "role": "web-library", diff --git a/plugins/signals/CHANGELOG.md b/plugins/signals/CHANGELOG.md index 85073ae23f..d135b27ade 100644 --- a/plugins/signals/CHANGELOG.md +++ b/plugins/signals/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-signals +## 0.0.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-signals-react@0.0.20-next.0 + ## 0.0.28 ### Patch Changes diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 962b1b6fda..4f390f1ddc 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-signals", - "version": "0.0.28", + "version": "0.0.29-next.0", "backstage": { "role": "frontend-plugin", "pluginId": "signals", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 988bbd7dbf..c7ceb95718 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs-addons-test-utils +## 2.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/plugin-catalog@1.33.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/plugin-techdocs@1.17.1-next.0 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/test-utils@1.7.16-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 2.0.2 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index 03e7809f22..639fc90db1 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "2.0.2", + "version": "2.0.3-next.0", "backstage": { "role": "web-library", "pluginId": "techdocs-addons", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 8d7934b086..a75cfe6671 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs-backend +## 2.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/plugin-catalog-node@2.1.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-techdocs-node@1.14.3-next.0 + ## 2.1.5 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index f128a954db..31d6797f15 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "2.1.5", + "version": "2.1.6-next.0", "description": "The Backstage backend plugin that renders technical documentation for your components", "backstage": { "role": "backend-plugin", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 617c97aed0..da2ac1bcb7 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 1.1.33 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index d7819741bc..86ef3743a0 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", - "version": "1.1.33", + "version": "1.1.34-next.0", "description": "Plugin module for contributed TechDocs Addons", "backstage": { "role": "frontend-plugin-module", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index da459e9bd2..fd02995625 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-node +## 1.14.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.21.0-next.0 + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/errors@1.2.7 + - @backstage/integration-aws-node@0.1.20 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.14.2 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index f4e4cd930d..163e8d3c12 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.14.2", + "version": "1.14.3-next.0", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", "backstage": { "role": "node-library", diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 8981a5df01..bca81bc172 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-react +## 1.3.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/version-bridge@1.0.12 + - @backstage/plugin-techdocs-common@0.1.1 + ## 1.3.8 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index e44b42417c..51acffebcc 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.3.8", + "version": "1.3.9-next.0", "description": "Shared frontend utilities for TechDocs and Addons", "backstage": { "role": "web-library", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 0572da3823..0a636c06f2 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-techdocs +## 1.17.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-react@1.10.5-next.0 + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/integration@1.21.0-next.0 + - @backstage/catalog-client@1.13.1-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/config@1.3.6 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/integration-react@1.2.16-next.0 + - @backstage/theme@0.7.2 + - @backstage/plugin-auth-react@0.1.25-next.0 + - @backstage/plugin-search-common@1.2.22 + - @backstage/plugin-techdocs-common@0.1.1 + - @backstage/plugin-techdocs-react@1.3.9-next.0 + ## 1.17.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 7852273cdb..91c49699ea 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.17.0", + "version": "1.17.1-next.0", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/techdocs/report.api.md b/plugins/techdocs/report.api.md index e7e9e4b916..9e4ed4ce45 100644 --- a/plugins/techdocs/report.api.md +++ b/plugins/techdocs/report.api.md @@ -66,11 +66,7 @@ export type ContentStateTypes = | 'CONTENT_FRESH'; // @public -export const CustomDocsPanel: ({ - config, - entities, - index, -}: { +export const CustomDocsPanel: (input: { config: PanelConfig; entities: Entity[]; index: number; @@ -151,12 +147,11 @@ export type DocsTableRow = { }; // @public -export const EmbeddedDocsRouter: ({ - children, - withSearch, -}: PropsWithChildren<{ - withSearch?: boolean; -}>) => JSX_2.Element; +export const EmbeddedDocsRouter: ( + input: PropsWithChildren<{ + withSearch?: boolean; + }>, +) => JSX_2.Element; // @public export const EntityListDocsGrid: ( @@ -208,12 +203,11 @@ export type EntityListDocsTableProps = { }; // @public -export const EntityTechdocsContent: ({ - children, - withSearch, -}: PropsWithChildren<{ - withSearch?: boolean; -}>) => JSX_2.Element; +export const EntityTechdocsContent: ( + input: PropsWithChildren<{ + withSearch?: boolean; + }>, +) => JSX_2.Element; // @public export const InfoCardGrid: (props: InfoCardGridProps) => JSX_2.Element | null; diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 1b21b58172..6149ad3704 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-user-settings-backend +## 0.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.7.1-next.0 + - @backstage/errors@1.2.7 + - @backstage/types@1.2.2 + - @backstage/plugin-auth-node@0.6.14-next.0 + - @backstage/plugin-signals-node@0.1.29-next.0 + - @backstage/plugin-user-settings-common@0.1.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index f96e813330..0dd097def1 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings-backend", - "version": "0.4.0", + "version": "0.4.1-next.0", "description": "The Backstage backend plugin to manage user settings", "backstage": { "role": "backend-plugin", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 0401f61fab..46a1ed955e 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.14.2-next.0 + - @backstage/plugin-catalog-react@2.0.1-next.0 + - @backstage/catalog-model@1.7.6 + - @backstage/core-app-api@1.19.6-next.0 + - @backstage/core-components@0.18.8-next.0 + - @backstage/core-plugin-api@1.12.4-next.0 + - @backstage/errors@1.2.7 + - @backstage/theme@0.7.2 + - @backstage/types@1.2.2 + - @backstage/plugin-signals-react@0.0.20-next.0 + - @backstage/plugin-user-settings-common@0.1.0 + ## 0.9.0 ### Minor Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 4178d04a39..8dbc35fd40 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.9.0", + "version": "0.9.1-next.0", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/yarn.lock b/yarn.lock index d1dbdea01c..14a3f7453e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5460,6 +5460,7 @@ __metadata: "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" "@backstage/types": "workspace:^" + "@opentelemetry/api": "npm:^1.9.0" lodash: "npm:^4.17.21" msw: "npm:^1.0.0" yaml: "npm:^2.0.0" @@ -7968,7 +7969,7 @@ __metadata: "@electric-sql/pglite": "npm:^0.3.0" "@manypkg/get-packages": "npm:^1.1.3" "@microsoft/api-documenter": "npm:^7.28.1" - "@microsoft/api-extractor": "npm:^7.55.1" + "@microsoft/api-extractor": "npm:^7.57.3" "@openapitools/openapi-generator-cli": "npm:^2.7.0" "@prettier/sync": "npm:^0.6.1" "@stoplight/spectral-core": "npm:^1.18.0" @@ -10165,22 +10166,6 @@ __metadata: languageName: node linkType: hard -"@isaacs/balanced-match@npm:^4.0.1": - version: 4.0.1 - resolution: "@isaacs/balanced-match@npm:4.0.1" - checksum: 10/102fbc6d2c0d5edf8f6dbf2b3feb21695a21bc850f11bc47c4f06aa83bd8884fde3fe9d6d797d619901d96865fdcb4569ac2a54c937992c48885c5e3d9967fe8 - languageName: node - linkType: hard - -"@isaacs/brace-expansion@npm:^5.0.0": - version: 5.0.1 - resolution: "@isaacs/brace-expansion@npm:5.0.1" - dependencies: - "@isaacs/balanced-match": "npm:^4.0.1" - checksum: 10/aec226065bc4285436a27379e08cc35bf94ef59f5098ac1c026495c9ba4ab33d851964082d3648d56d63eb90f2642867bd15a3e1b810b98beb1a8c14efce6a94 - languageName: node - linkType: hard - "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -11248,27 +11233,38 @@ __metadata: languageName: node linkType: hard -"@microsoft/api-extractor@npm:^7.55.1": - version: 7.55.2 - resolution: "@microsoft/api-extractor@npm:7.55.2" +"@microsoft/api-extractor-model@npm:7.33.1": + version: 7.33.1 + resolution: "@microsoft/api-extractor-model@npm:7.33.1" dependencies: - "@microsoft/api-extractor-model": "npm:7.32.2" "@microsoft/tsdoc": "npm:~0.16.0" "@microsoft/tsdoc-config": "npm:~0.18.0" - "@rushstack/node-core-library": "npm:5.19.1" - "@rushstack/rig-package": "npm:0.6.0" - "@rushstack/terminal": "npm:0.19.5" - "@rushstack/ts-command-line": "npm:5.1.5" + "@rushstack/node-core-library": "npm:5.20.1" + checksum: 10/cb267ca0020a68b84570bc99e974d050acf8b17a47f1999998a9dbc2ef81453f8188a93970a6b2274890a5dd5015502b6cebe94da06d3583e65ca490dabf4c1e + languageName: node + linkType: hard + +"@microsoft/api-extractor@npm:^7.57.3": + version: 7.57.3 + resolution: "@microsoft/api-extractor@npm:7.57.3" + dependencies: + "@microsoft/api-extractor-model": "npm:7.33.1" + "@microsoft/tsdoc": "npm:~0.16.0" + "@microsoft/tsdoc-config": "npm:~0.18.0" + "@rushstack/node-core-library": "npm:5.20.1" + "@rushstack/rig-package": "npm:0.7.1" + "@rushstack/terminal": "npm:0.22.1" + "@rushstack/ts-command-line": "npm:5.3.1" diff: "npm:~8.0.2" - lodash: "npm:~4.17.15" - minimatch: "npm:10.0.3" + lodash: "npm:~4.17.23" + minimatch: "npm:10.2.1" resolve: "npm:~1.22.1" semver: "npm:~7.5.4" source-map: "npm:~0.6.1" typescript: "npm:5.8.2" bin: api-extractor: bin/api-extractor - checksum: 10/56b7e9338ad18cf3dc6aaefd679b90117c9d5498dee5c621e868a5fe5002656e62d08267525eb880221d4588afcf6d680604249a9c2fb5faaba8f9c87be16b3e + checksum: 10/5b2a8c1833b97db4df49aa0d326b4591474a241da2c71489b5de9f24cc42f7579a2ff45d44bc52302c8f4ffb9dd0fbd6e101f19231003dafd31c0efc8100e2ba languageName: node linkType: hard @@ -17775,6 +17771,27 @@ __metadata: languageName: node linkType: hard +"@rushstack/node-core-library@npm:5.20.1": + version: 5.20.1 + resolution: "@rushstack/node-core-library@npm:5.20.1" + dependencies: + ajv: "npm:~8.13.0" + ajv-draft-04: "npm:~1.0.0" + ajv-formats: "npm:~3.0.1" + fs-extra: "npm:~11.3.0" + import-lazy: "npm:~4.0.0" + jju: "npm:~1.4.0" + resolve: "npm:~1.22.1" + semver: "npm:~7.5.4" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/bd05a400fd96818a6382df7bc6a284adc78bbc8ae81c40760f2fee56a4124f0e56a38e007745bcf39c7449913e97f182860c1a344b56a31b8ba8445c21c6c012 + languageName: node + linkType: hard + "@rushstack/problem-matcher@npm:0.1.1": version: 0.1.1 resolution: "@rushstack/problem-matcher@npm:0.1.1" @@ -17787,13 +17804,25 @@ __metadata: languageName: node linkType: hard -"@rushstack/rig-package@npm:0.6.0": - version: 0.6.0 - resolution: "@rushstack/rig-package@npm:0.6.0" +"@rushstack/problem-matcher@npm:0.2.1": + version: 0.2.1 + resolution: "@rushstack/problem-matcher@npm:0.2.1" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/62fda91629577a2f57de19be357cd0990da145ff4933f4d2cd48f423cc03b92fca06dd8916dcbaf1d307a201c104847c77066d45d79fd3c323c4949f0c99bf44 + languageName: node + linkType: hard + +"@rushstack/rig-package@npm:0.7.1": + version: 0.7.1 + resolution: "@rushstack/rig-package@npm:0.7.1" dependencies: resolve: "npm:~1.22.1" strip-json-comments: "npm:~3.1.1" - checksum: 10/6ca5d6615365dfe4d78fdc52a1a145bec92bba79d8692db91d05c774b4ec4d9dc6c41b31949708d0312896b9c1c205a0f0eaa32f51ac7b1780415ac51c76af71 + checksum: 10/080a80e5c36b6861ee4a9a6e5ad9692cc3861cfb9edd0b02e9438aaaaa5a6e1b6f65275469d9f997696487841c7bb7daa69bba69c5e7301426056437bf544138 languageName: node linkType: hard @@ -17813,6 +17842,22 @@ __metadata: languageName: node linkType: hard +"@rushstack/terminal@npm:0.22.1": + version: 0.22.1 + resolution: "@rushstack/terminal@npm:0.22.1" + dependencies: + "@rushstack/node-core-library": "npm:5.20.1" + "@rushstack/problem-matcher": "npm:0.2.1" + supports-color: "npm:~8.1.1" + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/fe4da212e11c60b8a6a2de9cb7658b03c510831d365c560eedf26a20fa85c62a45f1865cff99c2b252dcd773329fcd2347dd89e5e2efd5694d7746f0a8aec172 + languageName: node + linkType: hard + "@rushstack/ts-command-line@npm:5.1.5": version: 5.1.5 resolution: "@rushstack/ts-command-line@npm:5.1.5" @@ -17825,6 +17870,18 @@ __metadata: languageName: node linkType: hard +"@rushstack/ts-command-line@npm:5.3.1": + version: 5.3.1 + resolution: "@rushstack/ts-command-line@npm:5.3.1" + dependencies: + "@rushstack/terminal": "npm:0.22.1" + "@types/argparse": "npm:1.0.38" + argparse: "npm:~1.0.9" + string-argv: "npm:~0.3.1" + checksum: 10/51ca262eefbf07875f3e57fb402cba80e7ff36c14c0fc98c59af7be65407cafb4cbfe9b6738b549d91e687e40bb5720afb214efa1352a7a13c186241f92795f0 + languageName: node + linkType: hard + "@sagold/json-pointer@npm:^5.1.2": version: 5.1.2 resolution: "@sagold/json-pointer@npm:5.1.2" @@ -37921,7 +37978,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.15.0, lodash@npm:^4.16.4, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.15, lodash@npm:~4.17.21, lodash@npm:~4.17.23": +"lodash@npm:^4.15.0, lodash@npm:^4.16.4, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:~4.17.21, lodash@npm:~4.17.23": version: 4.17.23 resolution: "lodash@npm:4.17.23" checksum: 10/82504c88250f58da7a5a4289f57a4f759c44946c005dd232821c7688b5fcfbf4a6268f6a6cdde4b792c91edd2f3b5398c1d2a0998274432cff76def48735e233 @@ -39368,12 +39425,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:10.0.3": - version: 10.0.3 - resolution: "minimatch@npm:10.0.3" +"minimatch@npm:10.2.1": + version: 10.2.1 + resolution: "minimatch@npm:10.2.1" dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10/d5b8b2538b367f2cfd4aeef27539fddeee58d1efb692102b848e4a968a09780a302c530eb5aacfa8c57f7299155fb4b4e85219ad82664dcef5c66f657111d9b8 + brace-expansion: "npm:^5.0.2" + checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 languageName: node linkType: hard @@ -39396,11 +39453,11 @@ __metadata: linkType: hard "minimatch@npm:^10.1.1, minimatch@npm:^10.2.0, minimatch@npm:^10.2.1": - version: 10.2.1 - resolution: "minimatch@npm:10.2.1" + version: 10.2.3 + resolution: "minimatch@npm:10.2.3" dependencies: brace-expansion: "npm:^5.0.2" - checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 + checksum: 10/186c6a6ce9f7a79ae7776efc799c32d1a6670ebbcc2a8756e6cb6ec4aab7439a6ca6e592e1a6aac5f21674eefae5b19821b8fa95072a4f4567da1ae40eb6075d languageName: node linkType: hard