From a8a853eb1c42baaa0d3eb94476fe5a98d0619eb1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 17 Feb 2026 22:36:19 +0100 Subject: [PATCH 01/62] Add `translations export` and `translations import` CLI commands Adds tooling for exporting and importing translation strings to enable integration with external TMS tools like Smartling. The export command uses the TypeScript compiler API (ts-morph) to discover TranslationRef exports from all frontend plugin dependencies of the current package, extracting message keys and default values from the type system. The import command generates TranslationResource wiring from translated JSON files downloaded from a TMS. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/cli/src/index.ts | 1 + .../modules/translations/commands/export.ts | 119 ++++++++++++ .../modules/translations/commands/import.ts | 171 ++++++++++++++++++ .../cli/src/modules/translations/index.ts | 68 +++++++ .../translations/lib/discoverPackages.ts | 155 ++++++++++++++++ .../lib/extractTranslations.test.ts | 121 +++++++++++++ .../translations/lib/extractTranslations.ts | 133 ++++++++++++++ 7 files changed, 768 insertions(+) create mode 100644 packages/cli/src/modules/translations/commands/export.ts create mode 100644 packages/cli/src/modules/translations/commands/import.ts create mode 100644 packages/cli/src/modules/translations/index.ts create mode 100644 packages/cli/src/modules/translations/lib/discoverPackages.ts create mode 100644 packages/cli/src/modules/translations/lib/extractTranslations.test.ts create mode 100644 packages/cli/src/modules/translations/lib/extractTranslations.ts 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/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts new file mode 100644 index 0000000000..5366cdfeab --- /dev/null +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -0,0 +1,119 @@ +/* + * 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 { paths } from '../../../lib/paths'; +import fs from 'fs-extra'; +import { resolve as resolvePath } from 'node:path'; +import { + discoverFrontendPackages, + readTargetPackage, +} from '../lib/discoverPackages'; +import { + createTranslationProject, + extractTranslationRefsFromSourceFile, + TranslationRefInfo, +} from '../lib/extractTranslations'; + +interface ExportOptions { + output: string; +} + +export default async (options: ExportOptions) => { + const targetPackageJson = await readTargetPackage( + paths.targetDir, + paths.targetRoot, + ); + + const outputDir = resolvePath(paths.targetDir, options.output, 'messages'); + const manifestPath = resolvePath( + paths.targetDir, + options.output, + 'manifest.json', + ); + + const tsconfigPath = paths.resolveTargetRoot('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); + 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 + await fs.ensureDir(outputDir); + + for (const ref of allRefs) { + const filePath = resolvePath(outputDir, `${ref.id}.en.json`); + 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, { refs: manifest }, { spaces: 2 }); + + console.log( + `\nExported ${allRefs.length} translation ref(s) to ${options.output}/`, + ); + console.log(` Messages: ${options.output}/messages/.en.json`); + 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..e279239a38 --- /dev/null +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -0,0 +1,171 @@ +/* + * 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 { paths } from '../../../lib/paths'; +import fs from 'fs-extra'; +import { resolve as resolvePath, relative as relativePath } from 'node:path'; +import { readTargetPackage } from '../lib/discoverPackages'; + +interface ImportOptions { + input: string; + output: string; +} + +interface ManifestRefEntry { + package: string; + exportPath: string; + exportName: string; +} + +interface Manifest { + refs: Record; +} + +export default async (options: ImportOptions) => { + await readTargetPackage(paths.targetDir, paths.targetRoot); + + const inputDir = resolvePath(paths.targetDir, options.input); + const messagesDir = resolvePath(inputDir, 'messages'); + const manifestPath = resolvePath(inputDir, 'manifest.json'); + const outputPath = resolvePath(paths.targetDir, options.output); + + if (!(await fs.pathExists(manifestPath))) { + throw new Error( + `No manifest.json found at ${manifestPath}. ` + + 'Run "backstage-cli translations export" first.', + ); + } + + if (!(await fs.pathExists(messagesDir))) { + throw new Error( + `No messages directory found at ${messagesDir}. ` + + 'Run "backstage-cli translations export" first.', + ); + } + + const manifest: Manifest = await fs.readJson(manifestPath); + + // Find all translated (non-English) message files + const files = await fs.readdir(messagesDir); + const translatedFiles = files.filter( + f => f.endsWith('.json') && !f.endsWith('.en.json'), + ); + + if (translatedFiles.length === 0) { + console.log('No translated message files found.'); + console.log( + 'Add translated files as ..json in the messages/ directory.', + ); + return; + } + + // Group translations by ref ID + const translationsByRef = new Map(); + for (const file of translatedFiles) { + // Expected format: ..json + const match = file.match(/^(.+)\.([a-z]{2}(?:-[A-Z]{2})?)\.json$/); + if (!match) { + console.warn(` Warning: skipping file with unexpected name: ${file}`); + continue; + } + + const [, refId, language] = match; + if (!manifest.refs[refId]) { + console.warn( + ` Warning: skipping ${file} - ref '${refId}' not found in manifest`, + ); + continue; + } + + const existing = translationsByRef.get(refId) ?? []; + existing.push(language); + translationsByRef.set(refId, existing); + } + + if (translationsByRef.size === 0) { + console.log('No valid translation files found for known refs.'); + return; + } + + // Generate the wiring module + const importLines: string[] = []; + const resourceLines: string[] = []; + + importLines.push( + "import { createTranslationResource } from '@backstage/frontend-plugin-api';", + ); + + for (const [refId, languages] 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 messagesRelPath = relativePath( + resolvePath(outputPath, '..'), + messagesDir, + ); + + const translationEntries = languages + .sort() + .map( + lang => + ` ${JSON.stringify( + lang, + )}: () => import('./${messagesRelPath}/${refId}.${lang}.json'),`, + ) + .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'); + + console.log(`Generated translation resources at ${options.output}`); + console.log( + ` ${translationsByRef.size} ref(s), ${translatedFiles.length} translation file(s)`, + ); + console.log( + '\nImport this file in your app and pass the resources to your translation API setup.', + ); +}; diff --git a/packages/cli/src/modules/translations/index.ts b/packages/cli/src/modules/translations/index.ts new file mode 100644 index 0000000000..29207fa548 --- /dev/null +++ b/packages/cli/src/modules/translations/index.ts @@ -0,0 +1,68 @@ +/* + * 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'; + +export default createCliPlugin({ + pluginId: 'translations', + init: async reg => { + reg.addCommand({ + path: ['translations', 'export'], + description: + 'Export translation messages from all 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', + }, + }) + .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..895c254933 --- /dev/null +++ b/packages/cli/src/modules/translations/lib/discoverPackages.ts @@ -0,0 +1,155 @@ +/* + * 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, + PackageRole, +} from '@backstage/cli-node'; +import { resolve as resolvePath } from 'node:path'; +import fs from 'fs-extra'; + +/** + * Package roles that can contain frontend translation refs. + */ +const FRONTEND_ROLES: PackageRole[] = [ + 'frontend', + 'frontend-plugin', + 'frontend-plugin-module', + 'web-library', + 'common-library', +]; + +/** 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 dependencies of the given target + * package and resolves their entry point file paths. + */ +export async function discoverFrontendPackages( + targetPackageJson: BackstagePackageJson, +): Promise { + const allPackages = await PackageGraph.listTargetPackages(); + const packagesByName = new Map(allPackages.map(p => [p.packageJson.name, p])); + + // Collect all direct dependencies of the target package + const depNames = new Set([ + ...Object.keys(targetPackageJson.dependencies ?? {}), + ...Object.keys((targetPackageJson as any).devDependencies ?? {}), + ]); + + const result: DiscoveredPackage[] = []; + + for (const depName of depNames) { + const pkg = packagesByName.get(depName); + if (!pkg) { + continue; + } + + const role = pkg.packageJson.backstage?.role; + if (!role || !FRONTEND_ROLES.includes(role)) { + continue; + } + + const entryPoints = resolveEntryPoints(pkg.packageJson, pkg.dir); + if (entryPoints.size > 0) { + result.push({ + name: pkg.packageJson.name, + dir: pkg.dir, + entryPoints, + }); + } + } + + return result; +} + +/** + * Resolves the entry points of a package to absolute file paths. + * Uses the `exports` field from package.json, falling back to `main`/`types`. + */ +function resolveEntryPoints( + packageJson: BackstagePackageJson, + packageDir: string, +): Map { + const entryPoints = new Map(); + + const exports = (packageJson as any).exports as + | Record> + | undefined; + + if (exports) { + for (const [subpath, target] of Object.entries(exports)) { + // Skip package.json entry + if (subpath === './package.json') { + continue; + } + + // The target can be a string or a conditions map + const filePath = + typeof target === 'string' + ? target + : target?.import ?? target?.types ?? target?.default; + + if (typeof filePath === 'string') { + entryPoints.set(subpath, resolvePath(packageDir, filePath)); + } + } + } else { + // Fallback to main/types + const main = packageJson.types ?? packageJson.main; + if (main) { + entryPoints.set('.', resolvePath(packageDir, main)); + } + } + + return entryPoints; +} 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..8b46c63eff --- /dev/null +++ b/packages/cli/src/modules/translations/lib/extractTranslations.test.ts @@ -0,0 +1,121 @@ +/* + * 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', + }); + + // Verify a subset of messages + expect(refs[0].messages).toMatchObject({ + 'groupProfileCard.groupNotFound': 'Group not found', + 'membersListCard.title': 'Members', + 'membersListCard.subtitle': 'of {{groupName}}', + 'userProfileCard.userNotFound': 'User not found', + }); + + // Verify interpolation placeholders are preserved + expect(refs[0].messages['membersListCard.paginationLabel']).toBe( + ', page {{page}} of {{nbPages}}', + ); + + // Verify total message count + expect(Object.keys(refs[0].messages).length).toBe(26); + }); + + 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, + }); +} From d404ab30cafaae74d2fbe9c832f30f71481b3ee7 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 17 Feb 2026 23:29:31 +0100 Subject: [PATCH 02/62] cli: walk transitive deps and resolve npm packages for translation export The package discovery for the translations export command previously only looked at direct dependencies and only workspace packages. This changes it to recursively walk the full transitive dependency tree and resolve packages from node_modules when they aren't found in the workspace. Entry point resolution now also prefers .d.ts type declarations for npm-installed packages. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../modules/translations/commands/export.ts | 5 +- .../translations/lib/discoverPackages.ts | 127 +++++++++++++----- 2 files changed, 95 insertions(+), 37 deletions(-) diff --git a/packages/cli/src/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts index 5366cdfeab..e8371a7655 100644 --- a/packages/cli/src/modules/translations/commands/export.ts +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -55,7 +55,10 @@ export default async (options: ExportOptions) => { console.log( `Discovering frontend dependencies of ${targetPackageJson.name}...`, ); - const packages = await discoverFrontendPackages(targetPackageJson); + const packages = await discoverFrontendPackages( + targetPackageJson, + paths.targetDir, + ); console.log(`Found ${packages.length} frontend packages to scan`); console.log('Creating TypeScript project...'); diff --git a/packages/cli/src/modules/translations/lib/discoverPackages.ts b/packages/cli/src/modules/translations/lib/discoverPackages.ts index 895c254933..b8793accd5 100644 --- a/packages/cli/src/modules/translations/lib/discoverPackages.ts +++ b/packages/cli/src/modules/translations/lib/discoverPackages.ts @@ -19,7 +19,7 @@ import { PackageGraph, PackageRole, } from '@backstage/cli-node'; -import { resolve as resolvePath } from 'node:path'; +import { dirname, resolve as resolvePath } from 'node:path'; import fs from 'fs-extra'; /** @@ -71,54 +71,103 @@ export async function readTargetPackage( } /** - * Discovers frontend packages that are dependencies of the given target - * package and resolves their entry point file paths. + * 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 { - const allPackages = await PackageGraph.listTargetPackages(); - const packagesByName = new Map(allPackages.map(p => [p.packageJson.name, p])); - - // Collect all direct dependencies of the target package - const depNames = new Set([ - ...Object.keys(targetPackageJson.dependencies ?? {}), - ...Object.keys((targetPackageJson as any).devDependencies ?? {}), - ]); + // 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[] = []; - for (const depName of depNames) { - const pkg = packagesByName.get(depName); - if (!pkg) { - continue; - } + async function visit( + packageJson: BackstagePackageJson, + pkgDir: string, + includeDevDeps: boolean, + ) { + const deps: Record = { + ...packageJson.dependencies, + ...(includeDevDeps ? (packageJson as any).devDependencies : {}), + }; - const role = pkg.packageJson.backstage?.role; - if (!role || !FRONTEND_ROLES.includes(role)) { - continue; - } + for (const depName of Object.keys(deps)) { + if (visited.has(depName)) { + continue; + } + visited.add(depName); - const entryPoints = resolveEntryPoints(pkg.packageJson, pkg.dir); - if (entryPoints.size > 0) { - result.push({ - name: pkg.packageJson.name, - dir: pkg.dir, - entryPoints, - }); + 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 && FRONTEND_ROLES.includes(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. - * Uses the `exports` field from package.json, falling back to `main`/`types`. + * 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(); @@ -128,24 +177,30 @@ function resolveEntryPoints( if (exports) { for (const [subpath, target] of Object.entries(exports)) { - // Skip package.json entry if (subpath === './package.json') { continue; } - // The target can be a string or a conditions map - const filePath = - typeof target === 'string' - ? target - : target?.import ?? target?.types ?? target?.default; + 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 to main/types - const main = packageJson.types ?? packageJson.main; + // 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)); } From 356cff278fa6d20731d6eb3256bc6e46e5de3581 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 00:31:18 +0100 Subject: [PATCH 03/62] cli: add configurable --pattern option for translation message files Adds a --pattern option to both translations export and import commands that controls the file path layout of message files within the messages/ directory. The default pattern is {id}.{lang}.json (unchanged behavior), but users can pass e.g. --pattern '{lang}/{id}.json' for language-based directory grouping. The pattern is stored in the manifest so that import picks it up automatically. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../modules/translations/commands/export.ts | 31 +++-- .../modules/translations/commands/import.ts | 130 ++++++++++++------ .../cli/src/modules/translations/index.ts | 13 ++ .../translations/lib/messageFilePath.test.ts | 120 ++++++++++++++++ .../translations/lib/messageFilePath.ts | 83 +++++++++++ 5 files changed, 327 insertions(+), 50 deletions(-) create mode 100644 packages/cli/src/modules/translations/lib/messageFilePath.test.ts create mode 100644 packages/cli/src/modules/translations/lib/messageFilePath.ts diff --git a/packages/cli/src/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts index e8371a7655..ca8bd2c60b 100644 --- a/packages/cli/src/modules/translations/commands/export.ts +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -16,7 +16,7 @@ import { paths } from '../../../lib/paths'; import fs from 'fs-extra'; -import { resolve as resolvePath } from 'node:path'; +import { dirname, resolve as resolvePath } from 'node:path'; import { discoverFrontendPackages, readTargetPackage, @@ -26,9 +26,11 @@ import { extractTranslationRefsFromSourceFile, TranslationRefInfo, } from '../lib/extractTranslations'; +import { DEFAULT_LANGUAGE, formatMessagePath } from '../lib/messageFilePath'; interface ExportOptions { output: string; + pattern: string; } export default async (options: ExportOptions) => { @@ -37,7 +39,7 @@ export default async (options: ExportOptions) => { paths.targetRoot, ); - const outputDir = resolvePath(paths.targetDir, options.output, 'messages'); + const messagesDir = resolvePath(paths.targetDir, options.output, 'messages'); const manifestPath = resolvePath( paths.targetDir, options.output, @@ -95,11 +97,15 @@ export default async (options: ExportOptions) => { console.log(` ${ref.id} (${ref.packageName}, ${messageCount} messages)`); } - // Write message files - await fs.ensureDir(outputDir); - + // Write message files using the configured pattern for (const ref of allRefs) { - const filePath = resolvePath(outputDir, `${ref.id}.en.json`); + const relPath = formatMessagePath( + options.pattern, + ref.id, + DEFAULT_LANGUAGE, + ); + const filePath = resolvePath(messagesDir, relPath); + await fs.ensureDir(dirname(filePath)); await fs.writeJson(filePath, ref.messages, { spaces: 2 }); } @@ -112,11 +118,20 @@ export default async (options: ExportOptions) => { exportName: ref.exportName, }; } - await fs.writeJson(manifestPath, { refs: manifest }, { spaces: 2 }); + 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}/messages/.en.json`); + console.log(` Messages: ${options.output}/messages/${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 index e279239a38..b652eb524e 100644 --- a/packages/cli/src/modules/translations/commands/import.ts +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -16,12 +16,22 @@ import { paths } from '../../../lib/paths'; import fs from 'fs-extra'; -import { resolve as resolvePath, relative as relativePath } from 'node:path'; +import { + resolve as resolvePath, + relative as relativePath, + posix as posixPath, +} from 'node:path'; import { readTargetPackage } from '../lib/discoverPackages'; +import { + DEFAULT_LANGUAGE, + createMessagePathParser, + formatMessagePath, +} from '../lib/messageFilePath'; interface ImportOptions { input: string; output: string; + pattern: string; } interface ManifestRefEntry { @@ -31,6 +41,7 @@ interface ManifestRefEntry { } interface Manifest { + pattern?: string; refs: Record; } @@ -58,45 +69,56 @@ export default async (options: ImportOptions) => { const manifest: Manifest = await fs.readJson(manifestPath); - // Find all translated (non-English) message files - const files = await fs.readdir(messagesDir); - const translatedFiles = files.filter( - f => f.endsWith('.json') && !f.endsWith('.en.json'), - ); + // Use the pattern from manifest if available, falling back to the CLI default + const pattern = manifest.pattern ?? options.pattern; - if (translatedFiles.length === 0) { - console.log('No translated message files found.'); - console.log( - 'Add translated files as ..json in the messages/ directory.', - ); - return; - } + const parsePath = createMessagePathParser(pattern); - // Group translations by ref ID - const translationsByRef = new Map(); - for (const file of translatedFiles) { - // Expected format: ..json - const match = file.match(/^(.+)\.([a-z]{2}(?:-[A-Z]{2})?)\.json$/); - if (!match) { - console.warn(` Warning: skipping file with unexpected name: ${file}`); + // Discover all JSON files under the messages directory + const allFiles = await collectJsonFiles(messagesDir); + + // 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; } - const [, refId, language] = match; - if (!manifest.refs[refId]) { + if (parsed.lang === DEFAULT_LANGUAGE) { + continue; + } + + if (!manifest.refs[parsed.id]) { console.warn( - ` Warning: skipping ${file} - ref '${refId}' not found in manifest`, + ` Warning: skipping ${relPath} - ref '${parsed.id}' not found in manifest`, ); continue; } - const existing = translationsByRef.get(refId) ?? []; - existing.push(language); - translationsByRef.set(refId, existing); + 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 valid translation files found for known refs.'); + console.log('No translated message files found.'); + const example = formatMessagePath(pattern, '', 'sv'); + console.log( + `Add translated files as messages/${example} in the translations directory.`, + ); return; } @@ -108,7 +130,7 @@ export default async (options: ImportOptions) => { "import { createTranslationResource } from '@backstage/frontend-plugin-api';", ); - for (const [refId, languages] of [...translationsByRef.entries()].sort( + for (const [refId, entries] of [...translationsByRef.entries()].sort( ([a], [b]) => a.localeCompare(b), )) { const refEntry = manifest.refs[refId]; @@ -119,19 +141,17 @@ export default async (options: ImportOptions) => { importLines.push(`import { ${refEntry.exportName} } from '${importPath}';`); - const messagesRelPath = relativePath( - resolvePath(outputPath, '..'), - messagesDir, - ); - - const translationEntries = languages - .sort() - .map( - lang => - ` ${JSON.stringify( - lang, - )}: () => import('./${messagesRelPath}/${refId}.${lang}.json'),`, - ) + const translationEntries = entries + .sort((a, b) => a.lang.localeCompare(b.lang)) + .map(({ lang, relPath }) => { + const jsonRelPath = posixPath.normalize( + relativePath( + resolvePath(outputPath, '..'), + resolvePath(messagesDir, relPath), + ), + ); + return ` ${JSON.stringify(lang)}: () => import('./${jsonRelPath}'),`; + }) .join('\n'); resourceLines.push( @@ -161,11 +181,37 @@ export default async (options: ImportOptions) => { 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), ${translatedFiles.length} translation file(s)`, + ` ${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 index 29207fa548..7a7d33a28a 100644 --- a/packages/cli/src/modules/translations/index.ts +++ b/packages/cli/src/modules/translations/index.ts @@ -16,6 +16,7 @@ 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', @@ -33,6 +34,12 @@ export default createCliPlugin({ 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); @@ -58,6 +65,12 @@ export default createCliPlugin({ default: 'src/translations/resources.ts', description: 'Output path for the generated wiring module', }, + pattern: { + type: 'string', + default: DEFAULT_MESSAGE_PATTERN, + description: + 'File path pattern for message files, with {id} and {lang} placeholders', + }, }) .help() .parse(args); 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..6a6f3a8873 --- /dev/null +++ b/packages/cli/src/modules/translations/lib/messageFilePath.test.ts @@ -0,0 +1,120 @@ +/* + * 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( + 'org.en.json', + ); + }); + + it('formats with a different language', () => { + expect(formatMessagePath(DEFAULT_MESSAGE_PATTERN, 'catalog', 'sv')).toBe( + '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('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('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('dir/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('*.*.json'); + }); + + it('converts a language-directory pattern', () => { + expect(messagePatternToGlob('{lang}/{id}.json')).toBe('*/*.json'); + }); + }); + + describe('patternHasSubdirectories', () => { + it('returns false for flat patterns', () => { + expect(patternHasSubdirectories(DEFAULT_MESSAGE_PATTERN)).toBe(false); + }); + + 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..5f84c1ad13 --- /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. +// Supported placeholders: {id} (ref ID) and {lang} (language code). +export const DEFAULT_MESSAGE_PATTERN = '{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('/'); +} + +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}`, + ); + } +} From fd50cb3401543c6c9e8dcf3b13fca5136e5e20dc Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 00:41:23 +0100 Subject: [PATCH 04/62] docs: add changeset and documentation for translations CLI commands Adds a changeset for the new translations export/import CLI commands. Updates the internationalization docs with the CLI-based workflow as the recommended approach for managing translations, and adds the commands to the CLI reference. Also adds the internationalization page to the mkdocs navigation. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-translations-export-import.md | 9 + docs/plugins/internationalization.md | 180 +++++++++++++++++-- docs/tooling/cli/03-commands.md | 66 +++++++ mkdocs.yml | 1 + 4 files changed, 240 insertions(+), 16 deletions(-) create mode 100644 .changeset/cli-translations-export-import.md diff --git a/.changeset/cli-translations-export-import.md b/.changeset/cli-translations-export-import.md new file mode 100644 index 0000000000..38377d23ef --- /dev/null +++ b/.changeset/cli-translations-export-import.md @@ -0,0 +1,9 @@ +--- +'@backstage/cli': minor +--- + +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/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 4eb5e864d1..f1d5d8a81d 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 translation management systems (TMS) like Smartling, Crowdin, or Lokalise — 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 `{id}.{lang}.json` (e.g. `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/messages/en/catalog.json +translations/messages/zh/catalog.json +``` + +The pattern is stored in the manifest, so the `import` command automatically uses the same layout. + +#### Integration with a TMS + +The exported JSON files are standard key-value pairs compatible with most translation management systems. A typical workflow looks like: + +1. Run `translations export` to generate the source English files +2. Upload the `.en.json` files to your TMS +3. Download the translated files from your TMS into the `messages/` 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/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 0a0931f1db..3a3af67d5d 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 @@ -428,6 +429,71 @@ YAML file that can be referenced in the GitHub integration configuration. Usage: backstage-cli create-github-app ``` +## translations export + +Export translation messages from all frontend plugin dependencies of the current +package. 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, with {id} and {lang} + placeholders (default: "{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. + +```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") + --pattern File path pattern for message files, with {id} and {lang} + placeholders (default: "{id}.{lang}.json") + -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' From a808c9ef3ff0dcb48a4e0a77a54389d278c059ab Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 12:22:26 +0100 Subject: [PATCH 05/62] cli: use PackageRoles for role detection and remove redundant import --pattern Uses PackageRoles.getRoleInfo from cli-node to determine frontend packages by platform instead of a hardcoded role list. Removes the --pattern option from the import command since the pattern is always read from the manifest. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- docs/tooling/cli/03-commands.md | 11 +++++---- .../modules/translations/commands/import.ts | 9 +++++--- .../cli/src/modules/translations/index.ts | 6 ----- .../translations/lib/discoverPackages.ts | 23 ++++++++----------- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 3a3af67d5d..efdf197113 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -474,15 +474,16 @@ 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") - --pattern File path pattern for message files, with {id} and {lang} - placeholders (default: "{id}.{lang}.json") - -h, --help display help for command + --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 diff --git a/packages/cli/src/modules/translations/commands/import.ts b/packages/cli/src/modules/translations/commands/import.ts index b652eb524e..35b554ce30 100644 --- a/packages/cli/src/modules/translations/commands/import.ts +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -31,7 +31,6 @@ import { interface ImportOptions { input: string; output: string; - pattern: string; } interface ManifestRefEntry { @@ -69,8 +68,12 @@ export default async (options: ImportOptions) => { const manifest: Manifest = await fs.readJson(manifestPath); - // Use the pattern from manifest if available, falling back to the CLI default - const pattern = manifest.pattern ?? options.pattern; + 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); diff --git a/packages/cli/src/modules/translations/index.ts b/packages/cli/src/modules/translations/index.ts index 7a7d33a28a..0d7425ad41 100644 --- a/packages/cli/src/modules/translations/index.ts +++ b/packages/cli/src/modules/translations/index.ts @@ -65,12 +65,6 @@ export default createCliPlugin({ default: 'src/translations/resources.ts', description: 'Output path for the generated wiring module', }, - pattern: { - type: 'string', - default: DEFAULT_MESSAGE_PATTERN, - description: - 'File path pattern for message files, with {id} and {lang} placeholders', - }, }) .help() .parse(args); diff --git a/packages/cli/src/modules/translations/lib/discoverPackages.ts b/packages/cli/src/modules/translations/lib/discoverPackages.ts index b8793accd5..32c54da297 100644 --- a/packages/cli/src/modules/translations/lib/discoverPackages.ts +++ b/packages/cli/src/modules/translations/lib/discoverPackages.ts @@ -17,22 +17,11 @@ import { BackstagePackageJson, PackageGraph, - PackageRole, + PackageRoles, } from '@backstage/cli-node'; import { dirname, resolve as resolvePath } from 'node:path'; import fs from 'fs-extra'; -/** - * Package roles that can contain frontend translation refs. - */ -const FRONTEND_ROLES: PackageRole[] = [ - 'frontend', - 'frontend-plugin', - 'frontend-plugin-module', - 'web-library', - 'common-library', -]; - /** A discovered package with its entry points resolved to file paths. */ export interface DiscoveredPackage { /** The package name, e.g. '@backstage/plugin-org' */ @@ -141,7 +130,7 @@ export async function discoverFrontendPackages( } const role = depPkgJson.backstage?.role; - if (role && FRONTEND_ROLES.includes(role)) { + if (role && isFrontendRole(role)) { const entryPoints = resolveEntryPoints(depPkgJson, depDir, isWorkspace); if (entryPoints.size > 0) { result.push({ name: depName, dir: depDir, entryPoints }); @@ -208,3 +197,11 @@ function resolveEntryPoints( return entryPoints; } + +function isFrontendRole(role: string): boolean { + try { + return PackageRoles.getRoleInfo(role).platform === 'web'; + } catch { + return false; + } +} From dd5f0520176199c71a6b9161cd8bf74f19d68937 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 12:32:51 +0100 Subject: [PATCH 06/62] cli: make messages/ part of the configurable --pattern flag Moves the messages/ path segment from being hardcoded into the export and import commands to being part of the pattern itself. The default pattern is now messages/{id}.{lang}.json, giving full control over the directory structure under the translations output directory. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- docs/plugins/internationalization.md | 6 +++--- docs/tooling/cli/03-commands.md | 5 +++-- .../modules/translations/commands/export.ts | 12 ++++-------- .../modules/translations/commands/import.ts | 18 ++++++------------ .../translations/lib/messageFilePath.test.ts | 18 ++++++++++-------- .../translations/lib/messageFilePath.ts | 6 +++--- 6 files changed, 29 insertions(+), 36 deletions(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index f1d5d8a81d..0c62058e5a 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -382,7 +382,7 @@ const app = createApp({ #### Custom file patterns -By default, message files use the pattern `{id}.{lang}.json` (e.g. `catalog.en.json`). You can change this with the `--pattern` option: +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' @@ -391,8 +391,8 @@ yarn backstage-cli translations export --pattern '{lang}/{id}.json' This produces a directory structure grouped by language instead: ```text -translations/messages/en/catalog.json -translations/messages/zh/catalog.json +translations/en/catalog.json +translations/zh/catalog.json ``` The pattern is stored in the manifest, so the `import` command automatically uses the same layout. diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index efdf197113..44b9058f19 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -447,8 +447,9 @@ Usage: backstage-cli translations export [options] Options: --output Output directory for exported messages and manifest (default: "translations") - --pattern File path pattern for message files, with {id} and {lang} - placeholders (default: "{id}.{lang}.json") + --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 ``` diff --git a/packages/cli/src/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts index ca8bd2c60b..cf6630ae39 100644 --- a/packages/cli/src/modules/translations/commands/export.ts +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -39,12 +39,8 @@ export default async (options: ExportOptions) => { paths.targetRoot, ); - const messagesDir = resolvePath(paths.targetDir, options.output, 'messages'); - const manifestPath = resolvePath( - paths.targetDir, - options.output, - 'manifest.json', - ); + const outputDir = resolvePath(paths.targetDir, options.output); + const manifestPath = resolvePath(outputDir, 'manifest.json'); const tsconfigPath = paths.resolveTargetRoot('tsconfig.json'); if (!(await fs.pathExists(tsconfigPath))) { @@ -104,7 +100,7 @@ export default async (options: ExportOptions) => { ref.id, DEFAULT_LANGUAGE, ); - const filePath = resolvePath(messagesDir, relPath); + const filePath = resolvePath(outputDir, relPath); await fs.ensureDir(dirname(filePath)); await fs.writeJson(filePath, ref.messages, { spaces: 2 }); } @@ -132,6 +128,6 @@ export default async (options: ExportOptions) => { console.log( `\nExported ${allRefs.length} translation ref(s) to ${options.output}/`, ); - console.log(` Messages: ${options.output}/messages/${examplePath}`); + 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 index 35b554ce30..cab2030d1f 100644 --- a/packages/cli/src/modules/translations/commands/import.ts +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -48,7 +48,6 @@ export default async (options: ImportOptions) => { await readTargetPackage(paths.targetDir, paths.targetRoot); const inputDir = resolvePath(paths.targetDir, options.input); - const messagesDir = resolvePath(inputDir, 'messages'); const manifestPath = resolvePath(inputDir, 'manifest.json'); const outputPath = resolvePath(paths.targetDir, options.output); @@ -59,13 +58,6 @@ export default async (options: ImportOptions) => { ); } - if (!(await fs.pathExists(messagesDir))) { - throw new Error( - `No messages directory found at ${messagesDir}. ` + - 'Run "backstage-cli translations export" first.', - ); - } - const manifest: Manifest = await fs.readJson(manifestPath); if (!manifest.pattern) { @@ -77,8 +69,10 @@ export default async (options: ImportOptions) => { const parsePath = createMessagePathParser(pattern); - // Discover all JSON files under the messages directory - const allFiles = await collectJsonFiles(messagesDir); + // 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< @@ -120,7 +114,7 @@ export default async (options: ImportOptions) => { console.log('No translated message files found.'); const example = formatMessagePath(pattern, '', 'sv'); console.log( - `Add translated files as messages/${example} in the translations directory.`, + `Add translated files as ${example} in the translations directory.`, ); return; } @@ -150,7 +144,7 @@ export default async (options: ImportOptions) => { const jsonRelPath = posixPath.normalize( relativePath( resolvePath(outputPath, '..'), - resolvePath(messagesDir, relPath), + resolvePath(inputDir, relPath), ), ); return ` ${JSON.stringify(lang)}: () => import('./${jsonRelPath}'),`; diff --git a/packages/cli/src/modules/translations/lib/messageFilePath.test.ts b/packages/cli/src/modules/translations/lib/messageFilePath.test.ts index 6a6f3a8873..4c276e114c 100644 --- a/packages/cli/src/modules/translations/lib/messageFilePath.test.ts +++ b/packages/cli/src/modules/translations/lib/messageFilePath.test.ts @@ -26,13 +26,13 @@ describe('messageFilePath', () => { describe('formatMessagePath', () => { it('formats the default pattern', () => { expect(formatMessagePath(DEFAULT_MESSAGE_PATTERN, 'org', 'en')).toBe( - 'org.en.json', + 'messages/org.en.json', ); }); it('formats with a different language', () => { expect(formatMessagePath(DEFAULT_MESSAGE_PATTERN, 'catalog', 'sv')).toBe( - 'catalog.sv.json', + 'messages/catalog.sv.json', ); }); @@ -52,12 +52,12 @@ describe('messageFilePath', () => { describe('createMessagePathParser', () => { it('parses the default pattern', () => { const parse = createMessagePathParser(DEFAULT_MESSAGE_PATTERN); - expect(parse('org.en.json')).toEqual({ id: 'org', lang: 'en' }); + 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('plugin.notifications.sv.json')).toEqual({ + expect(parse('messages/plugin.notifications.sv.json')).toEqual({ id: 'plugin.notifications', lang: 'sv', }); @@ -71,7 +71,7 @@ describe('messageFilePath', () => { it('returns undefined for non-matching paths', () => { const parse = createMessagePathParser(DEFAULT_MESSAGE_PATTERN); expect(parse('not-a-match.txt')).toBeUndefined(); - expect(parse('dir/org.en.json')).toBeUndefined(); + expect(parse('other/org.en.json')).toBeUndefined(); }); it('returns undefined for invalid language code', () => { @@ -100,7 +100,9 @@ describe('messageFilePath', () => { describe('messagePatternToGlob', () => { it('converts the default pattern', () => { - expect(messagePatternToGlob(DEFAULT_MESSAGE_PATTERN)).toBe('*.*.json'); + expect(messagePatternToGlob(DEFAULT_MESSAGE_PATTERN)).toBe( + 'messages/*.*.json', + ); }); it('converts a language-directory pattern', () => { @@ -109,8 +111,8 @@ describe('messageFilePath', () => { }); describe('patternHasSubdirectories', () => { - it('returns false for flat patterns', () => { - expect(patternHasSubdirectories(DEFAULT_MESSAGE_PATTERN)).toBe(false); + it('returns true for the default pattern', () => { + expect(patternHasSubdirectories(DEFAULT_MESSAGE_PATTERN)).toBe(true); }); it('returns true for patterns with directories', () => { diff --git a/packages/cli/src/modules/translations/lib/messageFilePath.ts b/packages/cli/src/modules/translations/lib/messageFilePath.ts index 5f84c1ad13..0eb2547759 100644 --- a/packages/cli/src/modules/translations/lib/messageFilePath.ts +++ b/packages/cli/src/modules/translations/lib/messageFilePath.ts @@ -17,9 +17,9 @@ // The default language for exported translation messages. export const DEFAULT_LANGUAGE = 'en'; -// Default file path pattern for translation message files. -// Supported placeholders: {id} (ref ID) and {lang} (language code). -export const DEFAULT_MESSAGE_PATTERN = '{id}.{lang}.json'; +// 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( From cbb50c73da8592d79173f87764e62b77360aa5d0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 12:37:27 +0100 Subject: [PATCH 07/62] changeset: use patch bump for translations CLI commands Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-translations-export-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cli-translations-export-import.md b/.changeset/cli-translations-export-import.md index 38377d23ef..6631eebdfd 100644 --- a/.changeset/cli-translations-export-import.md +++ b/.changeset/cli-translations-export-import.md @@ -1,5 +1,5 @@ --- -'@backstage/cli': minor +'@backstage/cli': patch --- Added `translations export` and `translations import` commands for managing translation files. From c76d42020d8af44a6d1bf05ba00da874f29273d4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 12:43:03 +0100 Subject: [PATCH 08/62] docs: remove references to specific external translation systems Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- docs/plugins/internationalization.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 0c62058e5a..2770f76799 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -298,7 +298,7 @@ Go to the Settings page — you should see language switching buttons. Switch la ### Using the CLI for full translation workflows -When translating your app to other languages at scale — especially when working with translation management systems (TMS) like Smartling, Crowdin, or Lokalise — the Backstage CLI provides `translations export` and `translations import` commands that automate the extraction and wiring of translation messages across all your plugin dependencies. +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 @@ -397,13 +397,13 @@ translations/zh/catalog.json The pattern is stored in the manifest, so the `import` command automatically uses the same layout. -#### Integration with a TMS +#### Integration with external translation systems -The exported JSON files are standard key-value pairs compatible with most translation management systems. A typical workflow looks like: +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 TMS -3. Download the translated files from your TMS into the `messages/` directory +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). From 00472ed0be69712d6db29c37d4316379f7577e78 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 15:06:41 +0100 Subject: [PATCH 09/62] cli: update CLI report for translations commands Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/cli/cli-report.md | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 8979e91a82..03938dd6e2 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 ``` @@ -541,6 +542,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` ``` From 90f19f6164121bb2d76c12a8c83206e2ed146b76 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 18 Feb 2026 23:04:32 +0100 Subject: [PATCH 10/62] cli: address review feedback on translations commands - Fix Windows path separators in import by splitting on path.sep - Make extractTranslations test less brittle by not pinning exact message strings or total count - Remove unnecessary `as any` cast for devDependencies - Validate pattern in export command to fail fast on invalid patterns Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../modules/translations/commands/export.ts | 8 +++++++- .../modules/translations/commands/import.ts | 14 ++++++------- .../translations/lib/discoverPackages.ts | 2 +- .../lib/extractTranslations.test.ts | 20 ++++++++----------- .../translations/lib/messageFilePath.ts | 2 +- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/packages/cli/src/modules/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts index cf6630ae39..96b3ceb0c6 100644 --- a/packages/cli/src/modules/translations/commands/export.ts +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -26,7 +26,11 @@ import { extractTranslationRefsFromSourceFile, TranslationRefInfo, } from '../lib/extractTranslations'; -import { DEFAULT_LANGUAGE, formatMessagePath } from '../lib/messageFilePath'; +import { + DEFAULT_LANGUAGE, + formatMessagePath, + validatePattern, +} from '../lib/messageFilePath'; interface ExportOptions { output: string; @@ -34,6 +38,8 @@ interface ExportOptions { } export default async (options: ExportOptions) => { + validatePattern(options.pattern); + const targetPackageJson = await readTargetPackage( paths.targetDir, paths.targetRoot, diff --git a/packages/cli/src/modules/translations/commands/import.ts b/packages/cli/src/modules/translations/commands/import.ts index cab2030d1f..7275da4c24 100644 --- a/packages/cli/src/modules/translations/commands/import.ts +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -19,7 +19,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath, relative as relativePath, - posix as posixPath, + sep, } from 'node:path'; import { readTargetPackage } from '../lib/discoverPackages'; import { @@ -141,12 +141,12 @@ export default async (options: ImportOptions) => { const translationEntries = entries .sort((a, b) => a.lang.localeCompare(b.lang)) .map(({ lang, relPath }) => { - const jsonRelPath = posixPath.normalize( - relativePath( - resolvePath(outputPath, '..'), - resolvePath(inputDir, relPath), - ), - ); + const jsonRelPath = relativePath( + resolvePath(outputPath, '..'), + resolvePath(inputDir, relPath), + ) + .split(sep) + .join('/'); return ` ${JSON.stringify(lang)}: () => import('./${jsonRelPath}'),`; }) .join('\n'); diff --git a/packages/cli/src/modules/translations/lib/discoverPackages.ts b/packages/cli/src/modules/translations/lib/discoverPackages.ts index 32c54da297..c7a7602a7e 100644 --- a/packages/cli/src/modules/translations/lib/discoverPackages.ts +++ b/packages/cli/src/modules/translations/lib/discoverPackages.ts @@ -92,7 +92,7 @@ export async function discoverFrontendPackages( ) { const deps: Record = { ...packageJson.dependencies, - ...(includeDevDeps ? (packageJson as any).devDependencies : {}), + ...(includeDevDeps ? packageJson.devDependencies ?? {} : {}), }; for (const depName of Object.keys(deps)) { diff --git a/packages/cli/src/modules/translations/lib/extractTranslations.test.ts b/packages/cli/src/modules/translations/lib/extractTranslations.test.ts index 8b46c63eff..27b67db052 100644 --- a/packages/cli/src/modules/translations/lib/extractTranslations.test.ts +++ b/packages/cli/src/modules/translations/lib/extractTranslations.test.ts @@ -44,21 +44,17 @@ describe('extractTranslations', () => { exportName: 'orgTranslationRef', }); - // Verify a subset of messages - expect(refs[0].messages).toMatchObject({ - 'groupProfileCard.groupNotFound': 'Group not found', - 'membersListCard.title': 'Members', - 'membersListCard.subtitle': 'of {{groupName}}', - 'userProfileCard.userNotFound': 'User not found', - }); + 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.paginationLabel']).toBe( - ', page {{page}} of {{nbPages}}', + expect(refs[0].messages['membersListCard.subtitle']).toContain( + '{{groupName}}', ); - - // Verify total message count - expect(Object.keys(refs[0].messages).length).toBe(26); }); it('ignores non-TranslationRef exports', () => { diff --git a/packages/cli/src/modules/translations/lib/messageFilePath.ts b/packages/cli/src/modules/translations/lib/messageFilePath.ts index 0eb2547759..eb3dc8ea5c 100644 --- a/packages/cli/src/modules/translations/lib/messageFilePath.ts +++ b/packages/cli/src/modules/translations/lib/messageFilePath.ts @@ -64,7 +64,7 @@ export function patternHasSubdirectories(pattern: string): boolean { return pattern.includes('/'); } -function validatePattern(pattern: string) { +export function validatePattern(pattern: string) { if (!pattern.includes('{id}')) { throw new Error( `Invalid message file pattern: must contain {id} placeholder. Got: ${pattern}`, From bf716778198b42df703856601688d04f209c0d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sat, 21 Feb 2026 12:54:21 +0100 Subject: [PATCH 11/62] catalog: add metrics to the SCM events handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/orange-mugs-post-1.md | 7 ++++ .changeset/orange-mugs-post-2.md | 7 ++++ .../config/vocabularies/Backstage/accept.txt | 1 + .../providers/DefaultLocationStore.test.ts | 25 +++++++++++++++ .../src/providers/DefaultLocationStore.ts | 32 ++++++++++++++++--- .../GenericScmEventRefreshProvider.test.ts | 1 + .../GenericScmEventRefreshProvider.ts | 2 ++ .../src/service/CatalogPlugin.ts | 19 +++++++++++ .../src/service/createRouter.test.ts | 1 + plugins/catalog-node/package.json | 1 + plugins/catalog-node/report-alpha.api.md | 1 + .../DefaultCatalogScmEventsService.test.ts | 22 +++++++++++-- .../DefaultCatalogScmEventsService.ts | 26 +++++++++++++-- .../scmEvents/catalogScmEventsServiceRef.ts | 3 +- plugins/catalog-node/src/scmEvents/types.ts | 16 ++++++++++ yarn.lock | 1 + 16 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 .changeset/orange-mugs-post-1.md create mode 100644 .changeset/orange-mugs-post-2.md 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/.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/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/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index 26b09b9eea..a032fd732e 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -43,6 +43,7 @@ import { } from '@backstage/plugin-catalog-node/alpha'; import { eventsServiceRef } from '@backstage/plugin-events-node'; import { Permission } from '@backstage/plugin-permission-common'; +import { metrics } from '@opentelemetry/api'; import { merge } from 'lodash'; import { CatalogBuilder } from './CatalogBuilder'; import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha'; @@ -301,6 +302,24 @@ export const catalogPlugin = createBackendPlugin({ catalog, actionsRegistry, }); + + // Track SCM event message counts as a metric + const meter = metrics.getMeter('default'); + const scmEventsMessagesCounter = meter.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/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-node/package.json b/plugins/catalog-node/package.json index f8ce28451b..b06bd8ca08 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -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..92c3ea9b13 100644 --- a/plugins/catalog-node/src/scmEvents/types.ts +++ b/plugins/catalog-node/src/scmEvents/types.ts @@ -55,6 +55,22 @@ 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 + */ + 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/yarn.lock b/yarn.lock index 055c32c32b..ae9c764a3a 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" From 18a946c0187feb868991cb68f05bbde7d53e943f Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sat, 21 Feb 2026 11:37:14 -0600 Subject: [PATCH 12/62] Updated `@microsoft/api-extractor` to `7.57.2` Signed-off-by: Andre Wanlin --- .changeset/sixty-pianos-begin.md | 5 + packages/repo-tools/package.json | 2 +- .../api-reports/runApiExtraction.test.ts | 61 ++++++++ yarn.lock | 141 ++++++++++++------ 4 files changed, 161 insertions(+), 48 deletions(-) create mode 100644 .changeset/sixty-pianos-begin.md create mode 100644 packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.test.ts diff --git a/.changeset/sixty-pianos-begin.md b/.changeset/sixty-pianos-begin.md new file mode 100644 index 0000000000..45acb8cde0 --- /dev/null +++ b/.changeset/sixty-pianos-begin.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Updated `@microsoft/api-extractor` to `7.57.2` and added tests for `getTsDocConfig` diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 57632eedd7..53e4c81139 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -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.2", "@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/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/yarn.lock b/yarn.lock index cd20368bc2..42f9181b78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7968,7 +7968,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.2" "@openapitools/openapi-generator-cli": "npm:^2.7.0" "@prettier/sync": "npm:^0.6.1" "@stoplight/spectral-core": "npm:^1.18.0" @@ -10165,22 +10165,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 +11232,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.2": + version: 7.57.2 + resolution: "@microsoft/api-extractor@npm:7.57.2" + 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/7e6ff99a7ee07e34ae4e3d4e271ea794f20ba3b892932e94f3757f230b8f3d6a3f4c18c723c71d3bffdc7a5dd51c732201fc911089cdebae7a4a194d3e4de2e7 languageName: node linkType: hard @@ -17775,6 +17770,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 +17803,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 +17841,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 +17869,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" @@ -37871,7 +37927,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 @@ -39318,12 +39374,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, 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" dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10/d5b8b2538b367f2cfd4aeef27539fddeee58d1efb692102b848e4a968a09780a302c530eb5aacfa8c57f7299155fb4b4e85219ad82664dcef5c66f657111d9b8 + brace-expansion: "npm:^5.0.2" + checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 languageName: node linkType: hard @@ -39345,15 +39401,6 @@ __metadata: languageName: node 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" - dependencies: - brace-expansion: "npm:^5.0.2" - checksum: 10/d41c195ee1f2c70a75641088e36d0fa5fa286cb6fe48558e6d3bf3d95f640eda453c217707215389b12234df12175f65f338c0b841b36b0125177dbd6a80d026 - languageName: node - linkType: hard - "minimatch@npm:^5.0.1, minimatch@npm:^5.1.0": version: 5.1.6 resolution: "minimatch@npm:5.1.6" From ca49b96a8b8b4759af4f4f0e2f928d66191b2ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 13:22:30 +0100 Subject: [PATCH 13/62] Update plugins/catalog-node/src/scmEvents/types.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Fredrik Adelöw --- plugins/catalog-node/src/scmEvents/types.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-node/src/scmEvents/types.ts b/plugins/catalog-node/src/scmEvents/types.ts index 92c3ea9b13..72161cacde 100644 --- a/plugins/catalog-node/src/scmEvents/types.ts +++ b/plugins/catalog-node/src/scmEvents/types.ts @@ -58,7 +58,11 @@ export interface CatalogScmEventsService { /** * As a consumer of SCM events, mark that you have taken an action as a result - * of an SCM event. This + * 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: { /** From 619be54133a4dc7bccd652d7a01afdbeb5eee5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 14:41:36 +0100 Subject: [PATCH 14/62] auth: got rid of the sql report warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/tired-bushes-write.md | 5 +++++ plugins/auth-backend/migrations/20200619125845_init.js | 2 +- .../migrations/20220321100910_timestamptz_again.js | 2 +- plugins/auth-backend/report.sql.md | 3 --- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .changeset/tired-bushes-write.md 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/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/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 | From d2494d6319f982e684fce0bede9abbc6aa9fdc69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 14:24:44 +0100 Subject: [PATCH 15/62] touch up the catalog client docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/stupid-pans-hope.md | 5 +++ packages/catalog-client/src/CatalogClient.ts | 6 +-- packages/catalog-client/src/types/api.ts | 40 +++++++++---------- .../catalog-client/src/types/discovery.ts | 2 +- packages/catalog-client/src/types/fetch.ts | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 .changeset/stupid-pans-hope.md 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/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..c27e61bf22 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 */ diff --git a/packages/catalog-client/src/types/discovery.ts b/packages/catalog-client/src/types/discovery.ts index 19f304b1fd..ca1177c7ed 100644 --- a/packages/catalog-client/src/types/discovery.ts +++ b/packages/catalog-client/src/types/discovery.ts @@ -15,7 +15,7 @@ */ /** - * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + * This is a polymorphic version of `DiscoveryApi` / `DiscoveryService`. */ 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..81facdbac0 100644 --- a/packages/catalog-client/src/types/fetch.ts +++ b/packages/catalog-client/src/types/fetch.ts @@ -15,7 +15,7 @@ */ /** - * This is a copy of FetchApi, to avoid importing core-plugin-api. + * This is a polymorphic version of `FetchApi`. */ export type FetchApi = { fetch: typeof fetch; From 2ba6e22d9bdfea19763780379992296d97092a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 15:37:58 +0100 Subject: [PATCH 16/62] address review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- packages/catalog-client/src/types/api.ts | 2 +- packages/catalog-client/src/types/discovery.ts | 4 +++- packages/catalog-client/src/types/fetch.ts | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index c27e61bf22..c766b094b8 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -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 ca1177c7ed..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 polymorphic version of `DiscoveryApi` / `DiscoveryService`. + * 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 81facdbac0..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 polymorphic version of `FetchApi`. + * 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; From 06c2015e5b57c2518123c65ad13138d1c5875a79 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 16:19:49 +0100 Subject: [PATCH 17/62] Move parallel worker utilities to @backstage/cli-node Moves `runParallelWorkers`, `runWorkerQueueThreads`, `runWorkerThreads`, `parseParallelismOption`, and `getEnvironmentParallelism` from the CLI internal lib to the shared `@backstage/cli-node` package. This is part of the ongoing effort to make CLI modules independent of each other and the shared lib code. Signed-off-by: Patrik Oldsberg --- .changeset/cli-node-parallel-helpers.md | 5 ++ packages/cli-node/report.api.md | 55 +++++++++++++++++++ packages/cli-node/src/index.ts | 1 + packages/cli-node/src/parallel/index.ts | 28 ++++++++++ .../src/parallel}/parallel.test.ts | 0 .../lib => cli-node/src/parallel}/parallel.ts | 44 ++++++++++++++- .../src/modules/build/commands/repo/build.ts | 2 +- .../cli/src/modules/build/lib/buildBackend.ts | 3 +- .../src/modules/build/lib/buildFrontend.ts | 6 +- .../src/modules/build/lib/builder/packager.ts | 3 +- .../build/lib/packager/createDistWorkspace.ts | 2 +- .../src/modules/lint/commands/repo/lint.ts | 2 +- .../modules/migrate/commands/versions/bump.ts | 2 +- 13 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 .changeset/cli-node-parallel-helpers.md create mode 100644 packages/cli-node/src/parallel/index.ts rename packages/{cli/src/lib => cli-node/src/parallel}/parallel.test.ts (100%) rename packages/{cli/src/lib => cli-node/src/parallel}/parallel.ts (92%) diff --git a/.changeset/cli-node-parallel-helpers.md b/.changeset/cli-node-parallel-helpers.md new file mode 100644 index 0000000000..d4cea5c3c5 --- /dev/null +++ b/.changeset/cli-node-parallel-helpers.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': minor +--- + +Added parallel worker utilities: `runParallelWorkers`, `runWorkerQueueThreads`, `runWorkerThreads`, `parseParallelismOption`, and `getEnvironmentParallelism`. These were moved from the `@backstage/cli` internal code. diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index 55d2443643..960bbf9f59 100644 --- a/packages/cli-node/report.api.md +++ b/packages/cli-node/report.api.md @@ -86,6 +86,9 @@ export interface BackstagePackageJson { version: string; } +// @public +export function getEnvironmentParallelism(): number; + // @public export class GitUtils { static listChangedFiles(ref: string): Promise; @@ -200,4 +203,56 @@ export class PackageRoles { static getRoleFromPackage(pkgJson: unknown): PackageRole | undefined; static getRoleInfo(role: string): PackageRoleInfo; } + +// @public +export type ParallelismOption = boolean | string | number | null | undefined; + +// @public +export type ParallelWorkerOptions = { + parallelismFactor?: number; + parallelismSetting?: ParallelismOption; + items: Iterable; + worker: (item: TItem) => Promise; +}; + +// @public +export function parseParallelismOption(parallel: ParallelismOption): number; + +// @public +export function runParallelWorkers( + options: ParallelWorkerOptions, +): Promise; + +// @public +export function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, +): Promise; + +// @public +export function runWorkerThreads( + options: WorkerThreadsOptions, +): Promise; + +// @public +export type WorkerQueueThreadsOptions = { + items: Iterable; + workerFactory: ( + data: TData, + ) => + | ((item: TItem) => Promise) + | Promise<(item: TItem) => Promise>; + workerData?: TData; + threadCount?: number; +}; + +// @public +export type WorkerThreadsOptions = { + worker: ( + data: TData, + sendMessage: (message: TMessage) => void, + ) => Promise; + workerData?: TData; + threadCount?: number; + onMessage?: (message: TMessage) => void; +}; ``` diff --git a/packages/cli-node/src/index.ts b/packages/cli-node/src/index.ts index 1d3f3ec2ed..6d1c519b9e 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 './parallel'; export * from './roles'; diff --git a/packages/cli-node/src/parallel/index.ts b/packages/cli-node/src/parallel/index.ts new file mode 100644 index 0000000000..60cd2e28b2 --- /dev/null +++ b/packages/cli-node/src/parallel/index.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +export type { ParallelismOption, ParallelWorkerOptions } from './parallel'; +export { + parseParallelismOption, + getEnvironmentParallelism, + runParallelWorkers, + runWorkerQueueThreads, + runWorkerThreads, +} from './parallel'; +export type { + WorkerQueueThreadsOptions, + WorkerThreadsOptions, +} from './parallel'; diff --git a/packages/cli/src/lib/parallel.test.ts b/packages/cli-node/src/parallel/parallel.test.ts similarity index 100% rename from packages/cli/src/lib/parallel.test.ts rename to packages/cli-node/src/parallel/parallel.test.ts diff --git a/packages/cli/src/lib/parallel.ts b/packages/cli-node/src/parallel/parallel.ts similarity index 92% rename from packages/cli/src/lib/parallel.ts rename to packages/cli-node/src/parallel/parallel.ts index a4ca5dd13d..26c5803a93 100644 --- a/packages/cli/src/lib/parallel.ts +++ b/packages/cli-node/src/parallel/parallel.ts @@ -22,8 +22,21 @@ const defaultParallelism = Math.ceil(os.cpus().length / 2); const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; +/** + * Options for configuring parallelism. Can be a boolean, string, number, null, or undefined. + * - Boolean: true uses default parallelism (half of CPUs), false uses 1 + * - Number: explicit worker count + * - String: parsed as boolean or integer (e.g. "true", "4") + * + * @public + */ export type ParallelismOption = boolean | string | number | null | undefined; +/** + * Parses a parallelism option value into a concrete worker count. + * + * @public + */ export function parseParallelismOption(parallel: ParallelismOption): number { if (parallel === undefined || parallel === null) { return defaultParallelism; @@ -51,11 +64,21 @@ export function parseParallelismOption(parallel: ParallelismOption): number { ); } +/** + * Returns the parallelism value from the BACKSTAGE_CLI_BUILD_PARALLEL environment variable. + * + * @public + */ export function getEnvironmentParallelism() { return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); } -type ParallelWorkerOptions = { +/** + * Options for runParallelWorkers. + * + * @public + */ +export type ParallelWorkerOptions = { /** * Decides the number of parallel workers by multiplying * this with the configured parallelism, which defaults to 4. @@ -68,6 +91,11 @@ type ParallelWorkerOptions = { worker: (item: TItem) => Promise; }; +/** + * Runs items through a worker function in parallel across multiple async workers. + * + * @public + */ export async function runParallelWorkers( options: ParallelWorkerOptions, ) { @@ -119,6 +147,11 @@ type WorkerThreadMessage = message: unknown; }; +/** + * Options for runWorkerQueueThreads. + * + * @public + */ export type WorkerQueueThreadsOptions = { /** The items to process */ items: Iterable; @@ -149,6 +182,8 @@ export type WorkerQueueThreadsOptions = { /** * 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, @@ -250,6 +285,11 @@ function workerQueueThread( ); } +/** + * Options for runWorkerThreads. + * + * @public + */ export type WorkerThreadsOptions = { /** * A function that is called by each worker thread to produce a result. @@ -277,6 +317,8 @@ export type WorkerThreadsOptions = { /** * Spawns one or more worker threads using the `worker_threads` module. + * + * @public */ export async function runWorkerThreads( options: WorkerThreadsOptions, diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index e64fe9eff0..22c72c91dd 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -23,8 +23,8 @@ import { BackstagePackage, PackageGraph, PackageRoles, + runParallelWorkers, } from '@backstage/cli-node'; -import { runParallelWorkers } from '../../../../lib/parallel'; import { buildFrontend } from '../../lib/buildFrontend'; import { buildBackend } from '../../lib/buildBackend'; import { createScriptOptionsParser } from '../../../../lib/optionsParser'; diff --git a/packages/cli/src/modules/build/lib/buildBackend.ts b/packages/cli/src/modules/build/lib/buildBackend.ts index f377d068bd..ddf9b1f667 100644 --- a/packages/cli/src/modules/build/lib/buildBackend.ts +++ b/packages/cli/src/modules/build/lib/buildBackend.ts @@ -19,9 +19,8 @@ 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'; +import { PackageGraph, getEnvironmentParallelism } from '@backstage/cli-node'; const BUNDLE_FILE = 'bundle.tar.gz'; const SKELETON_FILE = 'skeleton.tar.gz'; diff --git a/packages/cli/src/modules/build/lib/buildFrontend.ts b/packages/cli/src/modules/build/lib/buildFrontend.ts index 7b0955a519..bb00de7951 100644 --- a/packages/cli/src/modules/build/lib/buildFrontend.ts +++ b/packages/cli/src/modules/build/lib/buildFrontend.ts @@ -17,9 +17,11 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { buildBundle, getModuleFederationRemoteOptions } from './bundler'; -import { getEnvironmentParallelism } from '../../../lib/parallel'; +import { + BackstagePackageJson, + getEnvironmentParallelism, +} from '@backstage/cli-node'; import { loadCliConfig } from '../../config/lib/config'; -import { BackstagePackageJson } from '@backstage/cli-node'; interface BuildAppOptions { targetDir: string; diff --git a/packages/cli/src/modules/build/lib/builder/packager.ts b/packages/cli/src/modules/build/lib/builder/packager.ts index 12017b694c..b0a34780d7 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -21,8 +21,7 @@ import { relative as relativePath, resolve as resolvePath } from 'node:path'; import { paths } from '../../../../lib/paths'; import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; -import { PackageRoles } from '@backstage/cli-node'; -import { runParallelWorkers } from '../../../../lib/parallel'; +import { PackageRoles, runParallelWorkers } from '@backstage/cli-node'; export function formatErrorMessage(error: any) { let msg = ''; diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 0f096a3127..b53bca62a6 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -41,8 +41,8 @@ import { PackageRoles, PackageGraph, PackageGraphNode, + runParallelWorkers, } 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 diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 458ccf1a63..0e17f97dd2 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -23,9 +23,9 @@ import { PackageGraph, BackstagePackageJson, Lockfile, + runWorkerQueueThreads, } from '@backstage/cli-node'; import { paths } from '../../../../lib/paths'; -import { runWorkerQueueThreads } from '../../../../lib/parallel'; import { createScriptOptionsParser } from '../../../../lib/optionsParser'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index ab65f8c604..06658cea5f 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -33,7 +33,7 @@ import { mapDependencies, YarnInfoInspectData, } from '../../../../lib/versioning'; -import { runParallelWorkers } from '../../../../lib/parallel'; +import { runParallelWorkers } from '@backstage/cli-node'; import { getManifestByReleaseLine, getManifestByVersion, From 649d3ca3b6481c4981b8b04bb74bfafb18b0c439 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 16:49:55 +0100 Subject: [PATCH 18/62] Remove dead parallelism options and narrow public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The parallelism fields on bundler types (BundlingOptions, BuildOptions, BackendBundlingOptions) and createDistWorkspace Options were defined but never read — fully dead code. Likewise the parallelismSetting option on ParallelWorkerOptions was never passed by any caller. Also narrows the cli-node public API to only export the three runner functions and their option types, keeping getEnvironmentParallelism and parseParallelismOption as internal utilities. Signed-off-by: Patrik Oldsberg --- .changeset/cli-node-parallel-helpers.md | 2 +- packages/cli-node/report.api.md | 10 -------- packages/cli-node/src/parallel/index.ts | 4 +-- .../cli-node/src/parallel/parallel.test.ts | 6 ++++- packages/cli-node/src/parallel/parallel.ts | 25 ++----------------- .../cli/src/modules/build/lib/buildBackend.ts | 3 +-- .../src/modules/build/lib/buildFrontend.ts | 6 +---- .../src/modules/build/lib/bundler/types.ts | 3 --- .../build/lib/packager/createDistWorkspace.ts | 5 ---- 9 files changed, 11 insertions(+), 53 deletions(-) diff --git a/.changeset/cli-node-parallel-helpers.md b/.changeset/cli-node-parallel-helpers.md index d4cea5c3c5..d34f063a27 100644 --- a/.changeset/cli-node-parallel-helpers.md +++ b/.changeset/cli-node-parallel-helpers.md @@ -2,4 +2,4 @@ '@backstage/cli-node': minor --- -Added parallel worker utilities: `runParallelWorkers`, `runWorkerQueueThreads`, `runWorkerThreads`, `parseParallelismOption`, and `getEnvironmentParallelism`. These were moved from the `@backstage/cli` internal code. +Added parallel worker utilities: `runParallelWorkers`, `runWorkerQueueThreads`, and `runWorkerThreads`. These were moved from the `@backstage/cli` internal code. diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index 960bbf9f59..67085b815f 100644 --- a/packages/cli-node/report.api.md +++ b/packages/cli-node/report.api.md @@ -86,9 +86,6 @@ export interface BackstagePackageJson { version: string; } -// @public -export function getEnvironmentParallelism(): number; - // @public export class GitUtils { static listChangedFiles(ref: string): Promise; @@ -204,20 +201,13 @@ export class PackageRoles { static getRoleInfo(role: string): PackageRoleInfo; } -// @public -export type ParallelismOption = boolean | string | number | null | undefined; - // @public export type ParallelWorkerOptions = { parallelismFactor?: number; - parallelismSetting?: ParallelismOption; items: Iterable; worker: (item: TItem) => Promise; }; -// @public -export function parseParallelismOption(parallel: ParallelismOption): number; - // @public export function runParallelWorkers( options: ParallelWorkerOptions, diff --git a/packages/cli-node/src/parallel/index.ts b/packages/cli-node/src/parallel/index.ts index 60cd2e28b2..0b7c46712d 100644 --- a/packages/cli-node/src/parallel/index.ts +++ b/packages/cli-node/src/parallel/index.ts @@ -14,10 +14,8 @@ * limitations under the License. */ -export type { ParallelismOption, ParallelWorkerOptions } from './parallel'; +export type { ParallelWorkerOptions } from './parallel'; export { - parseParallelismOption, - getEnvironmentParallelism, runParallelWorkers, runWorkerQueueThreads, runWorkerThreads, diff --git a/packages/cli-node/src/parallel/parallel.test.ts b/packages/cli-node/src/parallel/parallel.test.ts index 389e22102b..51a09377ed 100644 --- a/packages/cli-node/src/parallel/parallel.test.ts +++ b/packages/cli-node/src/parallel/parallel.test.ts @@ -66,14 +66,18 @@ describe('getEnvironmentParallelism', () => { }); describe('runParallelWorkers', () => { + afterEach(() => { + delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; + }); + it('executes work in parallel', async () => { const started = new Array(); const done = new Array(); const waiting = new Array<() => void>(); + process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '4'; const work = runParallelWorkers({ items: [0, 1, 2, 3, 4], - parallelismSetting: 4, parallelismFactor: 0.5, // 2 at a time worker: async item => { started.push(item); diff --git a/packages/cli-node/src/parallel/parallel.ts b/packages/cli-node/src/parallel/parallel.ts index 26c5803a93..1ec960adb0 100644 --- a/packages/cli-node/src/parallel/parallel.ts +++ b/packages/cli-node/src/parallel/parallel.ts @@ -22,21 +22,8 @@ const defaultParallelism = Math.ceil(os.cpus().length / 2); const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; -/** - * Options for configuring parallelism. Can be a boolean, string, number, null, or undefined. - * - Boolean: true uses default parallelism (half of CPUs), false uses 1 - * - Number: explicit worker count - * - String: parsed as boolean or integer (e.g. "true", "4") - * - * @public - */ export type ParallelismOption = boolean | string | number | null | undefined; -/** - * Parses a parallelism option value into a concrete worker count. - * - * @public - */ export function parseParallelismOption(parallel: ParallelismOption): number { if (parallel === undefined || parallel === null) { return defaultParallelism; @@ -64,11 +51,6 @@ export function parseParallelismOption(parallel: ParallelismOption): number { ); } -/** - * Returns the parallelism value from the BACKSTAGE_CLI_BUILD_PARALLEL environment variable. - * - * @public - */ export function getEnvironmentParallelism() { return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); } @@ -86,7 +68,6 @@ export type ParallelWorkerOptions = { * Defaults to 1. */ parallelismFactor?: number; - parallelismSetting?: ParallelismOption; items: Iterable; worker: (item: TItem) => Promise; }; @@ -99,10 +80,8 @@ export type ParallelWorkerOptions = { export async function runParallelWorkers( options: ParallelWorkerOptions, ) { - const { parallelismFactor = 1, parallelismSetting, items, worker } = options; - const parallelism = parallelismSetting - ? parseParallelismOption(parallelismSetting) - : getEnvironmentParallelism(); + const { parallelismFactor = 1, items, worker } = options; + const parallelism = getEnvironmentParallelism(); const sharedIterator = items[Symbol.iterator](); const sharedIterable = { diff --git a/packages/cli/src/modules/build/lib/buildBackend.ts b/packages/cli/src/modules/build/lib/buildBackend.ts index ddf9b1f667..bf2ebf16ba 100644 --- a/packages/cli/src/modules/build/lib/buildBackend.ts +++ b/packages/cli/src/modules/build/lib/buildBackend.ts @@ -20,7 +20,7 @@ import { resolve as resolvePath } from 'node:path'; import * as tar from 'tar'; import { createDistWorkspace } from './packager'; import { buildPackage, Output } from './builder'; -import { PackageGraph, getEnvironmentParallelism } from '@backstage/cli-node'; +import { PackageGraph } from '@backstage/cli-node'; const BUNDLE_FILE = 'bundle.tar.gz'; const SKELETON_FILE = 'skeleton.tar.gz'; @@ -52,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 bb00de7951..6a5785a5b9 100644 --- a/packages/cli/src/modules/build/lib/buildFrontend.ts +++ b/packages/cli/src/modules/build/lib/buildFrontend.ts @@ -17,10 +17,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { buildBundle, getModuleFederationRemoteOptions } from './bundler'; -import { - BackstagePackageJson, - getEnvironmentParallelism, -} from '@backstage/cli-node'; +import { BackstagePackageJson } from '@backstage/cli-node'; import { loadCliConfig } from '../../config/lib/config'; interface BuildAppOptions { @@ -39,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/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 b53bca62a6..f0bbaa4ff1 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -86,11 +86,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. From c8237e212d5122d567f0791c7460f8d46c4d78e1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 17:20:16 +0100 Subject: [PATCH 19/62] Rename parallelism env var to BACKSTAGE_CLI_PARALLELISM Renames from BACKSTAGE_CLI_BUILD_PARALLEL to the more general BACKSTAGE_CLI_PARALLELISM. The old name is still supported but logs a one-time deprecation warning. Signed-off-by: Patrik Oldsberg --- .../cli-node/src/parallel/parallel.test.ts | 39 ++++++++++++++++--- packages/cli-node/src/parallel/parallel.ts | 19 ++++++++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/cli-node/src/parallel/parallel.test.ts b/packages/cli-node/src/parallel/parallel.test.ts index 51a09377ed..2ab713d9aa 100644 --- a/packages/cli-node/src/parallel/parallel.test.ts +++ b/packages/cli-node/src/parallel/parallel.test.ts @@ -50,24 +50,51 @@ describe('parseParallelismOption', () => { }); describe('getEnvironmentParallelism', () => { + afterEach(() => { + delete process.env.BACKSTAGE_CLI_PARALLELISM; + delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; + }); + it('reads the parallelism setting from the environment', () => { - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '2'; + process.env.BACKSTAGE_CLI_PARALLELISM = '2'; expect(getEnvironmentParallelism()).toBe(2); - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'true'; + process.env.BACKSTAGE_CLI_PARALLELISM = 'true'; expect(getEnvironmentParallelism()).toBe(defaultParallelism); - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = 'false'; + process.env.BACKSTAGE_CLI_PARALLELISM = 'false'; expect(getEnvironmentParallelism()).toBe(1); - delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; + delete process.env.BACKSTAGE_CLI_PARALLELISM; expect(getEnvironmentParallelism()).toBe(defaultParallelism); }); + + it('supports the deprecated BACKSTAGE_CLI_BUILD_PARALLEL with a warning', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + + process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '3'; + expect(getEnvironmentParallelism()).toBe(3); + expect(warnSpy).toHaveBeenCalledWith( + 'The BACKSTAGE_CLI_BUILD_PARALLEL environment variable is deprecated, use BACKSTAGE_CLI_PARALLELISM instead', + ); + + warnSpy.mockClear(); + expect(getEnvironmentParallelism()).toBe(3); + expect(warnSpy).not.toHaveBeenCalled(); + + warnSpy.mockRestore(); + }); + + it('prefers BACKSTAGE_CLI_PARALLELISM over the deprecated variable', () => { + process.env.BACKSTAGE_CLI_PARALLELISM = '5'; + process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '3'; + expect(getEnvironmentParallelism()).toBe(5); + }); }); describe('runParallelWorkers', () => { afterEach(() => { - delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; + delete process.env.BACKSTAGE_CLI_PARALLELISM; }); it('executes work in parallel', async () => { @@ -75,7 +102,7 @@ describe('runParallelWorkers', () => { const done = new Array(); const waiting = new Array<() => void>(); - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '4'; + process.env.BACKSTAGE_CLI_PARALLELISM = '4'; const work = runParallelWorkers({ items: [0, 1, 2, 3, 4], parallelismFactor: 0.5, // 2 at a time diff --git a/packages/cli-node/src/parallel/parallel.ts b/packages/cli-node/src/parallel/parallel.ts index 1ec960adb0..91a39980bd 100644 --- a/packages/cli-node/src/parallel/parallel.ts +++ b/packages/cli-node/src/parallel/parallel.ts @@ -20,7 +20,8 @@ import { Worker } from 'node:worker_threads'; const defaultParallelism = Math.ceil(os.cpus().length / 2); -const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; +const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_PARALLELISM'; +const DEPRECATED_PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; export type ParallelismOption = boolean | string | number | null | undefined; @@ -51,8 +52,22 @@ export function parseParallelismOption(parallel: ParallelismOption): number { ); } +let hasWarnedDeprecation = false; + export function getEnvironmentParallelism() { - return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); + if (process.env[PARALLEL_ENV_VAR] !== undefined) { + return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); + } + if (process.env[DEPRECATED_PARALLEL_ENV_VAR] !== undefined) { + if (!hasWarnedDeprecation) { + hasWarnedDeprecation = true; + console.warn( + `The ${DEPRECATED_PARALLEL_ENV_VAR} environment variable is deprecated, use ${PARALLEL_ENV_VAR} instead`, + ); + } + return parseParallelismOption(process.env[DEPRECATED_PARALLEL_ENV_VAR]); + } + return defaultParallelism; } /** From fbf382f1f80a4a44f7baca12dba3f1f0e32f7aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 22:37:18 +0100 Subject: [PATCH 20/62] catalog: minor internal optimisation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/metal-humans-move.md | 5 + .../operations/stitcher/markForStitching.ts | 52 +-------- .../catalog-backend/src/database/util.test.ts | 110 ++++++++++++++++++ plugins/catalog-backend/src/database/util.ts | 45 ++++++- 4 files changed, 161 insertions(+), 51 deletions(-) create mode 100644 .changeset/metal-humans-move.md create mode 100644 plugins/catalog-backend/src/database/util.test.ts 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/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..c69c2b362e --- /dev/null +++ b/plugins/catalog-backend/src/database/util.test.ts @@ -0,0 +1,110 @@ +/* + * 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'; + +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', () => { + 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 timestamps: number[] = []; + const fn = jest.fn().mockImplementation(async () => { + timestamps.push(Date.now()); + if (timestamps.length <= 3) { + throw pgDeadlockError(); + } + return 'done'; + }); + + const baseMs = 50; + await retryOnDeadlock(fn, mockKnex('pg'), 3, baseMs); + + expect(fn).toHaveBeenCalledTimes(4); + // Verify delays increase (with some tolerance for timing) + const delay1 = timestamps[1] - timestamps[0]; + const delay2 = timestamps[2] - timestamps[1]; + const delay3 = timestamps[3] - timestamps[2]; + expect(delay1).toBeGreaterThanOrEqual(baseMs * 0.8); + expect(delay2).toBeGreaterThanOrEqual(baseMs * 2 * 0.8); + expect(delay3).toBeGreaterThanOrEqual(baseMs * 4 * 0.8); + }); + + 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; +} From 2eb3cf6344c14fb35f00f02d8d5ad6b7944e66d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Feb 2026 23:38:14 +0100 Subject: [PATCH 21/62] use fake timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../catalog-backend/src/database/util.test.ts | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/plugins/catalog-backend/src/database/util.test.ts b/plugins/catalog-backend/src/database/util.test.ts index c69c2b362e..b3f11b7f92 100644 --- a/plugins/catalog-backend/src/database/util.test.ts +++ b/plugins/catalog-backend/src/database/util.test.ts @@ -17,6 +17,10 @@ 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; } @@ -28,6 +32,10 @@ function pgDeadlockError(): Error & { code: string } { } 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); @@ -77,26 +85,33 @@ describe('retryOnDeadlock', () => { }); it('applies exponential backoff between retries', async () => { - const timestamps: number[] = []; - const fn = jest.fn().mockImplementation(async () => { - timestamps.push(Date.now()); - if (timestamps.length <= 3) { - throw pgDeadlockError(); - } - return 'done'; + 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; - await retryOnDeadlock(fn, mockKnex('pg'), 3, baseMs); + const result = await retryOnDeadlock(fn, mockKnex('pg'), 3, baseMs); + expect(result).toBe('done'); expect(fn).toHaveBeenCalledTimes(4); - // Verify delays increase (with some tolerance for timing) - const delay1 = timestamps[1] - timestamps[0]; - const delay2 = timestamps[2] - timestamps[1]; - const delay3 = timestamps[3] - timestamps[2]; - expect(delay1).toBeGreaterThanOrEqual(baseMs * 0.8); - expect(delay2).toBeGreaterThanOrEqual(baseMs * 2 * 0.8); - expect(delay3).toBeGreaterThanOrEqual(baseMs * 4 * 0.8); + // 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 () => { From 4f0c7ec86a72058a2cea1ac2e88ae52d0e324b32 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 00:41:17 +0100 Subject: [PATCH 22/62] Address PR review feedback - Rename runParallelWorkers to runConcurrentTasks, return void - Rename ParallelWorkerOptions to ConcurrentTasksOptions - Rename parallelismFactor to concurrencyFactor - Remove unused runWorkerThreads and WorkerThreadsOptions - Rename workerData to context in WorkerQueueThreadsOptions - Drop threadCount from public API types - Rename env var to BACKSTAGE_CLI_CONCURRENCY - Make cli-node changeset a patch Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-node-parallel-helpers.md | 4 +- packages/cli-node/report.api.md | 47 ++-- packages/cli-node/src/parallel/index.ts | 12 +- .../cli-node/src/parallel/parallel.test.ts | 175 ++++----------- packages/cli-node/src/parallel/parallel.ts | 209 +++++------------- .../src/modules/build/commands/repo/build.ts | 10 +- .../src/modules/build/lib/builder/packager.ts | 4 +- .../build/lib/packager/createDistWorkspace.ts | 6 +- .../src/modules/lint/commands/repo/lint.ts | 2 +- .../modules/migrate/commands/versions/bump.ts | 10 +- 10 files changed, 140 insertions(+), 339 deletions(-) diff --git a/.changeset/cli-node-parallel-helpers.md b/.changeset/cli-node-parallel-helpers.md index d34f063a27..5ad7ad7f4d 100644 --- a/.changeset/cli-node-parallel-helpers.md +++ b/.changeset/cli-node-parallel-helpers.md @@ -1,5 +1,5 @@ --- -'@backstage/cli-node': minor +'@backstage/cli-node': patch --- -Added parallel worker utilities: `runParallelWorkers`, `runWorkerQueueThreads`, and `runWorkerThreads`. These were moved from the `@backstage/cli` internal code. +Added `runConcurrentTasks` and `runWorkerQueueThreads` utilities, moved from the `@backstage/cli` internal code. diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index 67085b815f..902eff2b91 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; @@ -202,47 +209,23 @@ export class PackageRoles { } // @public -export type ParallelWorkerOptions = { - parallelismFactor?: number; - items: Iterable; - worker: (item: TItem) => Promise; -}; +export function runConcurrentTasks( + options: ConcurrentTasksOptions, +): Promise; // @public -export function runParallelWorkers( - options: ParallelWorkerOptions, -): Promise; - -// @public -export function runWorkerQueueThreads( - options: WorkerQueueThreadsOptions, +export function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, ): Promise; // @public -export function runWorkerThreads( - options: WorkerThreadsOptions, -): Promise; - -// @public -export type WorkerQueueThreadsOptions = { +export type WorkerQueueThreadsOptions = { items: Iterable; workerFactory: ( - data: TData, + context: TContext, ) => | ((item: TItem) => Promise) | Promise<(item: TItem) => Promise>; - workerData?: TData; - threadCount?: number; -}; - -// @public -export type WorkerThreadsOptions = { - worker: ( - data: TData, - sendMessage: (message: TMessage) => void, - ) => Promise; - workerData?: TData; - threadCount?: number; - onMessage?: (message: TMessage) => void; + context?: TContext; }; ``` diff --git a/packages/cli-node/src/parallel/index.ts b/packages/cli-node/src/parallel/index.ts index 0b7c46712d..7aadbafe70 100644 --- a/packages/cli-node/src/parallel/index.ts +++ b/packages/cli-node/src/parallel/index.ts @@ -14,13 +14,5 @@ * limitations under the License. */ -export type { ParallelWorkerOptions } from './parallel'; -export { - runParallelWorkers, - runWorkerQueueThreads, - runWorkerThreads, -} from './parallel'; -export type { - WorkerQueueThreadsOptions, - WorkerThreadsOptions, -} from './parallel'; +export type { ConcurrentTasksOptions, WorkerQueueThreadsOptions } from './parallel'; +export { runConcurrentTasks, runWorkerQueueThreads } from './parallel'; diff --git a/packages/cli-node/src/parallel/parallel.test.ts b/packages/cli-node/src/parallel/parallel.test.ts index 2ab713d9aa..b0d3be3769 100644 --- a/packages/cli-node/src/parallel/parallel.test.ts +++ b/packages/cli-node/src/parallel/parallel.test.ts @@ -14,87 +14,11 @@ * limitations under the License. */ -import os from 'node:os'; -import { - parseParallelismOption, - getEnvironmentParallelism, - runParallelWorkers, - runWorkerQueueThreads, - runWorkerThreads, -} from './parallel'; +import { runConcurrentTasks, runWorkerQueueThreads } 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', () => { +describe('runConcurrentTasks', () => { afterEach(() => { - delete process.env.BACKSTAGE_CLI_PARALLELISM; - delete process.env.BACKSTAGE_CLI_BUILD_PARALLEL; - }); - - it('reads the parallelism setting from the environment', () => { - process.env.BACKSTAGE_CLI_PARALLELISM = '2'; - expect(getEnvironmentParallelism()).toBe(2); - - process.env.BACKSTAGE_CLI_PARALLELISM = 'true'; - expect(getEnvironmentParallelism()).toBe(defaultParallelism); - - process.env.BACKSTAGE_CLI_PARALLELISM = 'false'; - expect(getEnvironmentParallelism()).toBe(1); - - delete process.env.BACKSTAGE_CLI_PARALLELISM; - expect(getEnvironmentParallelism()).toBe(defaultParallelism); - }); - - it('supports the deprecated BACKSTAGE_CLI_BUILD_PARALLEL with a warning', () => { - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); - - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '3'; - expect(getEnvironmentParallelism()).toBe(3); - expect(warnSpy).toHaveBeenCalledWith( - 'The BACKSTAGE_CLI_BUILD_PARALLEL environment variable is deprecated, use BACKSTAGE_CLI_PARALLELISM instead', - ); - - warnSpy.mockClear(); - expect(getEnvironmentParallelism()).toBe(3); - expect(warnSpy).not.toHaveBeenCalled(); - - warnSpy.mockRestore(); - }); - - it('prefers BACKSTAGE_CLI_PARALLELISM over the deprecated variable', () => { - process.env.BACKSTAGE_CLI_PARALLELISM = '5'; - process.env.BACKSTAGE_CLI_BUILD_PARALLEL = '3'; - expect(getEnvironmentParallelism()).toBe(5); - }); -}); - -describe('runParallelWorkers', () => { - afterEach(() => { - delete process.env.BACKSTAGE_CLI_PARALLELISM; + delete process.env.BACKSTAGE_CLI_CONCURRENCY; }); it('executes work in parallel', async () => { @@ -102,10 +26,10 @@ describe('runParallelWorkers', () => { const done = new Array(); const waiting = new Array<() => void>(); - process.env.BACKSTAGE_CLI_PARALLELISM = '4'; - const work = runParallelWorkers({ + process.env.BACKSTAGE_CLI_CONCURRENCY = '4'; + const work = runConcurrentTasks({ items: [0, 1, 2, 3, 4], - parallelismFactor: 0.5, // 2 at a time + concurrencyFactor: 0.5, // 2 at a time worker: async item => { started.push(item); await new Promise(resolve => { @@ -141,9 +65,9 @@ describe('runParallelWorkers', () => { const done = new Array(); const waiting = new Array<() => void>(); - const work = runParallelWorkers({ + const work = runConcurrentTasks({ items: [0, 1, 2, 3, 4], - parallelismFactor: 0, // 1 at a time + concurrencyFactor: 0, // 1 at a time worker: async item => { started.push(item); await new Promise(resolve => { @@ -178,6 +102,45 @@ describe('runParallelWorkers', () => { 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(); + }); }); describe('runWorkerQueueThreads', () => { @@ -186,10 +149,9 @@ describe('runWorkerQueueThreads', () => { const sharedView = new Uint8Array(sharedData); const results = await runWorkerQueueThreads({ - threadCount: 4, - workerData: sharedData, + context: sharedData, items: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - workerFactory: data => { + workerFactory: (data: SharedArrayBuffer) => { const view = new Uint8Array(data); return async (i: number) => { @@ -205,42 +167,3 @@ describe('runWorkerQueueThreads', () => { 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-node/src/parallel/parallel.ts b/packages/cli-node/src/parallel/parallel.ts index 91a39980bd..f925ed91e4 100644 --- a/packages/cli-node/src/parallel/parallel.ts +++ b/packages/cli-node/src/parallel/parallel.ts @@ -18,93 +18,98 @@ 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 defaultConcurrency = Math.max(Math.ceil(os.cpus().length / 2), 1); -const PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_PARALLELISM'; -const DEPRECATED_PARALLEL_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; +const CONCURRENCY_ENV_VAR = 'BACKSTAGE_CLI_CONCURRENCY'; +const DEPRECATED_CONCURRENCY_ENV_VAR = 'BACKSTAGE_CLI_BUILD_PARALLEL'; -export type ParallelismOption = boolean | string | number | null | undefined; +type ConcurrencyOption = 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) { +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 parallel; - } else if (typeof parallel === 'string') { - if (parallel === 'true') { - return parseParallelismOption(true); - } else if (parallel === 'false') { - return parseParallelismOption(false); + return value; + } else if (typeof value === 'string') { + if (value === 'true') { + return parseConcurrencyOption(true); + } else if (value === 'false') { + return parseConcurrencyOption(false); } - const parsed = Number(parallel); + const parsed = Number(value); if (Number.isInteger(parsed)) { - return parseParallelismOption(parsed); + return parseConcurrencyOption(parsed); } } throw Error( - `Parallel option value '${parallel}' is not a boolean or integer`, + `Concurrency option value '${value}' is not a boolean or integer`, ); } let hasWarnedDeprecation = false; -export function getEnvironmentParallelism() { - if (process.env[PARALLEL_ENV_VAR] !== undefined) { - return parseParallelismOption(process.env[PARALLEL_ENV_VAR]); +function getEnvironmentConcurrency() { + if (process.env[CONCURRENCY_ENV_VAR] !== undefined) { + return parseConcurrencyOption(process.env[CONCURRENCY_ENV_VAR]); } - if (process.env[DEPRECATED_PARALLEL_ENV_VAR] !== undefined) { + if (process.env[DEPRECATED_CONCURRENCY_ENV_VAR] !== undefined) { if (!hasWarnedDeprecation) { hasWarnedDeprecation = true; console.warn( - `The ${DEPRECATED_PARALLEL_ENV_VAR} environment variable is deprecated, use ${PARALLEL_ENV_VAR} instead`, + `The ${DEPRECATED_CONCURRENCY_ENV_VAR} environment variable is deprecated, use ${CONCURRENCY_ENV_VAR} instead`, ); } - return parseParallelismOption(process.env[DEPRECATED_PARALLEL_ENV_VAR]); + return parseConcurrencyOption( + process.env[DEPRECATED_CONCURRENCY_ENV_VAR], + ); } - return defaultParallelism; + return defaultConcurrency; } /** - * Options for runParallelWorkers. + * Options for {@link runConcurrentTasks}. * * @public */ -export type ParallelWorkerOptions = { +export type ConcurrentTasksOptions = { /** - * Decides the number of parallel workers by multiplying - * this with the configured parallelism, which defaults to 4. + * Decides the number of concurrent workers by multiplying + * this with the configured concurrency. * * Defaults to 1. */ - parallelismFactor?: number; + concurrencyFactor?: number; items: Iterable; worker: (item: TItem) => Promise; }; /** - * Runs items through a worker function in parallel across multiple async workers. + * Runs items through a worker function concurrently across multiple async workers. * * @public */ -export async function runParallelWorkers( - options: ParallelWorkerOptions, -) { - const { parallelismFactor = 1, items, worker } = options; - const parallelism = getEnvironmentParallelism(); +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(parallelismFactor * parallelism), 1); - return Promise.all( + const workerCount = Math.max( + Math.floor(concurrencyFactor * concurrency), + 1, + ); + await Promise.all( Array(workerCount) .fill(0) .map(async () => { @@ -142,11 +147,11 @@ type WorkerThreadMessage = }; /** - * Options for runWorkerQueueThreads. + * Options for {@link runWorkerQueueThreads}. * * @public */ -export type WorkerQueueThreadsOptions = { +export type WorkerQueueThreadsOptions = { /** The items to process */ items: Iterable; /** @@ -158,19 +163,17 @@ export type WorkerQueueThreadsOptions = { * 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 + * 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: ( - data: TData, + context: TContext, ) => | ((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; + /** Context data supplied to each worker factory */ + context?: TContext; }; /** @@ -179,15 +182,13 @@ export type WorkerQueueThreadsOptions = { * * @public */ -export async function runWorkerQueueThreads( - options: WorkerQueueThreadsOptions, +export async function runWorkerQueueThreads( + options: WorkerQueueThreadsOptions, ): Promise { const items = Array.from(options.items); - const { - workerFactory, - workerData, - threadCount = Math.min(getEnvironmentParallelism(), items.length), - } = options; + const workerFactory = options.workerFactory; + const workerData = options.context; + const threadCount = Math.min(getEnvironmentConcurrency(), items.length); const iterator = items[Symbol.iterator](); const results = new Array(); @@ -278,101 +279,3 @@ function workerQueueThread( error => parentPort.postMessage({ type: 'error', error }), ); } - -/** - * Options for runWorkerThreads. - * - * @public - */ -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. - * - * @public - */ -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/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index 22c72c91dd..6c99ebb0af 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -23,7 +23,7 @@ import { BackstagePackage, PackageGraph, PackageRoles, - runParallelWorkers, + runConcurrentTasks, } from '@backstage/cli-node'; import { buildFrontend } from '../../lib/buildFrontend'; import { buildBackend } from '../../lib/buildBackend'; @@ -100,9 +100,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 +121,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/lib/builder/packager.ts b/packages/cli/src/modules/build/lib/builder/packager.ts index b0a34780d7..77b1e2b134 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -21,7 +21,7 @@ import { relative as relativePath, resolve as resolvePath } from 'node:path'; import { paths } from '../../../../lib/paths'; import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; -import { PackageRoles, runParallelWorkers } from '@backstage/cli-node'; +import { PackageRoles, runConcurrentTasks } from '@backstage/cli-node'; export function formatErrorMessage(error: any) { let msg = ''; @@ -126,7 +126,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/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index f0bbaa4ff1..296355e2dd 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -41,7 +41,7 @@ import { PackageRoles, PackageGraph, PackageGraphNode, - runParallelWorkers, + runConcurrentTasks, } from '@backstage/cli-node'; import { createTypeDistProject } from '../../../../lib/typeDistProject'; @@ -220,7 +220,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 || [])], { @@ -363,7 +363,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/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 0e17f97dd2..07e4eac3ff 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -107,7 +107,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { const 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), diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index 06658cea5f..a0a73dd78e 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -33,7 +33,7 @@ import { mapDependencies, YarnInfoInspectData, } from '../../../../lib/versioning'; -import { runParallelWorkers } from '@backstage/cli-node'; +import { runConcurrentTasks } from '@backstage/cli-node'; import { getManifestByReleaseLine, getManifestByVersion, @@ -145,8 +145,8 @@ export default async (opts: OptionValues) => { // 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 +182,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'); From 1dfc3436d9a104e18e9b8ba04cb8b01ba07e4d9d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 01:05:15 +0100 Subject: [PATCH 23/62] cli: address review feedback from freben Fix whitespace alignment in CLI command summary, improve export command description to clarify it operates from an app context, and update the corresponding docs section. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- docs/tooling/cli/03-commands.md | 6 +++--- packages/cli/src/modules/translations/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tooling/cli/03-commands.md b/docs/tooling/cli/03-commands.md index 44b9058f19..7bea50588a 100644 --- a/docs/tooling/cli/03-commands.md +++ b/docs/tooling/cli/03-commands.md @@ -24,7 +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 +translations [command] Translation message management clean Delete cache directories [DEPRECATED] build-workspace [packages...] Builds a temporary dist workspace from the provided packages @@ -431,8 +431,8 @@ Usage: backstage-cli create-github-app ## translations export -Export translation messages from all frontend plugin dependencies of the current -package. This command must be run from within a package directory (e.g. +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, diff --git a/packages/cli/src/modules/translations/index.ts b/packages/cli/src/modules/translations/index.ts index 0d7425ad41..702b0f4f49 100644 --- a/packages/cli/src/modules/translations/index.ts +++ b/packages/cli/src/modules/translations/index.ts @@ -24,7 +24,7 @@ export default createCliPlugin({ reg.addCommand({ path: ['translations', 'export'], description: - 'Export translation messages from all frontend plugins to JSON files', + 'Export translation messages from an app and all of its frontend plugins to JSON files', execute: async ({ args }) => { const argv = await yargs() .options({ From 67958e2d6c37adde53d37801c051bfa071d90658 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 10:59:43 +0100 Subject: [PATCH 24/62] Fix prettier formatting Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/cli-node/src/parallel/index.ts | 5 ++++- packages/cli-node/src/parallel/parallel.ts | 9 ++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/cli-node/src/parallel/index.ts b/packages/cli-node/src/parallel/index.ts index 7aadbafe70..f8f9d4d51f 100644 --- a/packages/cli-node/src/parallel/index.ts +++ b/packages/cli-node/src/parallel/index.ts @@ -14,5 +14,8 @@ * limitations under the License. */ -export type { ConcurrentTasksOptions, WorkerQueueThreadsOptions } from './parallel'; +export type { + ConcurrentTasksOptions, + WorkerQueueThreadsOptions, +} from './parallel'; export { runConcurrentTasks, runWorkerQueueThreads } from './parallel'; diff --git a/packages/cli-node/src/parallel/parallel.ts b/packages/cli-node/src/parallel/parallel.ts index f925ed91e4..9d36852351 100644 --- a/packages/cli-node/src/parallel/parallel.ts +++ b/packages/cli-node/src/parallel/parallel.ts @@ -65,9 +65,7 @@ function getEnvironmentConcurrency() { `The ${DEPRECATED_CONCURRENCY_ENV_VAR} environment variable is deprecated, use ${CONCURRENCY_ENV_VAR} instead`, ); } - return parseConcurrencyOption( - process.env[DEPRECATED_CONCURRENCY_ENV_VAR], - ); + return parseConcurrencyOption(process.env[DEPRECATED_CONCURRENCY_ENV_VAR]); } return defaultConcurrency; } @@ -105,10 +103,7 @@ export async function runConcurrentTasks( [Symbol.iterator]: () => sharedIterator, }; - const workerCount = Math.max( - Math.floor(concurrencyFactor * concurrency), - 1, - ); + const workerCount = Math.max(Math.floor(concurrencyFactor * concurrency), 1); await Promise.all( Array(workerCount) .fill(0) From 90ffb545528a9c0c718450e977b3a0a1a19fff23 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 11:21:51 +0100 Subject: [PATCH 25/62] Rename parallel/ to concurrency/ and split into separate files Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../cli-node/src/concurrency/concurrency.ts | 70 ++++++++++++ .../src/{parallel => concurrency}/index.ts | 9 +- .../runConcurrentTasks.test.ts} | 27 +---- .../src/concurrency/runConcurrentTasks.ts | 62 +++++++++++ .../concurrency/runWorkerQueueThreads.test.ts | 42 +++++++ .../runWorkerQueueThreads.ts} | 103 +----------------- packages/cli-node/src/index.ts | 2 +- 7 files changed, 181 insertions(+), 134 deletions(-) create mode 100644 packages/cli-node/src/concurrency/concurrency.ts rename packages/cli-node/src/{parallel => concurrency}/index.ts (69%) rename packages/cli-node/src/{parallel/parallel.test.ts => concurrency/runConcurrentTasks.test.ts} (83%) create mode 100644 packages/cli-node/src/concurrency/runConcurrentTasks.ts create mode 100644 packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts rename packages/cli-node/src/{parallel/parallel.ts => concurrency/runWorkerQueueThreads.ts} (65%) 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/parallel/index.ts b/packages/cli-node/src/concurrency/index.ts similarity index 69% rename from packages/cli-node/src/parallel/index.ts rename to packages/cli-node/src/concurrency/index.ts index f8f9d4d51f..3ff4067a20 100644 --- a/packages/cli-node/src/parallel/index.ts +++ b/packages/cli-node/src/concurrency/index.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -export type { - ConcurrentTasksOptions, - WorkerQueueThreadsOptions, -} from './parallel'; -export { runConcurrentTasks, runWorkerQueueThreads } from './parallel'; +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/parallel/parallel.test.ts b/packages/cli-node/src/concurrency/runConcurrentTasks.test.ts similarity index 83% rename from packages/cli-node/src/parallel/parallel.test.ts rename to packages/cli-node/src/concurrency/runConcurrentTasks.test.ts index b0d3be3769..382a85d297 100644 --- a/packages/cli-node/src/parallel/parallel.test.ts +++ b/packages/cli-node/src/concurrency/runConcurrentTasks.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { runConcurrentTasks, runWorkerQueueThreads } from './parallel'; +import { runConcurrentTasks } from './runConcurrentTasks'; describe('runConcurrentTasks', () => { afterEach(() => { @@ -142,28 +142,3 @@ describe('runConcurrentTasks', () => { warnSpy.mockRestore(); }); }); - -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/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..20e71531ab --- /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/parallel/parallel.ts b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts similarity index 65% rename from packages/cli-node/src/parallel/parallel.ts rename to packages/cli-node/src/concurrency/runWorkerQueueThreads.ts index 9d36852351..d1974dba90 100644 --- a/packages/cli-node/src/parallel/parallel.ts +++ b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts @@ -14,106 +14,9 @@ * limitations under the License. */ -import os from 'node:os'; import { ErrorLike } from '@backstage/errors'; import { Worker } from 'node:worker_threads'; - -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; - -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; -} - -/** - * 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); - } - }), - ); -} +import { getEnvironmentConcurrency } from './concurrency'; type WorkerThreadMessage = | { @@ -135,10 +38,6 @@ type WorkerThreadMessage = | { type: 'error'; error: ErrorLike; - } - | { - type: 'message'; - message: unknown; }; /** diff --git a/packages/cli-node/src/index.ts b/packages/cli-node/src/index.ts index 6d1c519b9e..5540666a05 100644 --- a/packages/cli-node/src/index.ts +++ b/packages/cli-node/src/index.ts @@ -22,5 +22,5 @@ export * from './git'; export * from './monorepo'; -export * from './parallel'; +export * from './concurrency'; export * from './roles'; From 951924d0c26372c370862e87cc5e3195f7543783 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 11:25:17 +0100 Subject: [PATCH 26/62] Update CLI changeset message Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-internal-refactor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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`. From f467a4126e7a549f1eb4fad6ce2268f7e2670597 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 11:38:23 +0100 Subject: [PATCH 27/62] Return object from runWorkerQueueThreads Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/cli-node/report.api.md | 4 +++- .../cli-node/src/concurrency/runWorkerQueueThreads.test.ts | 2 +- packages/cli-node/src/concurrency/runWorkerQueueThreads.ts | 4 ++-- packages/cli/src/modules/lint/commands/repo/lint.ts | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index 902eff2b91..b3d8fe5641 100644 --- a/packages/cli-node/report.api.md +++ b/packages/cli-node/report.api.md @@ -216,7 +216,9 @@ export function runConcurrentTasks( // @public export function runWorkerQueueThreads( options: WorkerQueueThreadsOptions, -): Promise; +): Promise<{ + results: TResult[]; +}>; // @public export type WorkerQueueThreadsOptions = { diff --git a/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts b/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts index 20e71531ab..5dd2cda438 100644 --- a/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts +++ b/packages/cli-node/src/concurrency/runWorkerQueueThreads.test.ts @@ -21,7 +21,7 @@ describe('runWorkerQueueThreads', () => { const sharedData = new SharedArrayBuffer(10); const sharedView = new Uint8Array(sharedData); - const results = await runWorkerQueueThreads({ + const { results } = await runWorkerQueueThreads({ context: sharedData, items: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], workerFactory: (data: SharedArrayBuffer) => { diff --git a/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts index d1974dba90..2d2a3b37e4 100644 --- a/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts +++ b/packages/cli-node/src/concurrency/runWorkerQueueThreads.ts @@ -78,7 +78,7 @@ export type WorkerQueueThreadsOptions = { */ export async function runWorkerQueueThreads( options: WorkerQueueThreadsOptions, -): Promise { +): Promise<{ results: TResult[] }> { const items = Array.from(options.items); const workerFactory = options.workerFactory; const workerData = options.context; @@ -134,7 +134,7 @@ export async function runWorkerQueueThreads( }), ); - return results; + return { results }; } /* istanbul ignore next */ diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 07e4eac3ff..98a100fe3e 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -105,7 +105,7 @@ 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 context: { fix: Boolean(opts.fix), From d0469f605a143d6305ff0113d422282ef550e074 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Mon, 23 Feb 2026 06:08:29 -0600 Subject: [PATCH 28/62] Updated to latest patch version Signed-off-by: Andre Wanlin --- .changeset/sixty-pianos-begin.md | 2 +- packages/repo-tools/package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.changeset/sixty-pianos-begin.md b/.changeset/sixty-pianos-begin.md index 45acb8cde0..98db19c21d 100644 --- a/.changeset/sixty-pianos-begin.md +++ b/.changeset/sixty-pianos-begin.md @@ -2,4 +2,4 @@ '@backstage/repo-tools': patch --- -Updated `@microsoft/api-extractor` to `7.57.2` and added tests for `getTsDocConfig` +Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 53e4c81139..bc27ae4a42 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -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.57.2", + "@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/yarn.lock b/yarn.lock index 42f9181b78..9ff489bb39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7968,7 +7968,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.57.2" + "@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" @@ -11243,9 +11243,9 @@ __metadata: languageName: node linkType: hard -"@microsoft/api-extractor@npm:^7.57.2": - version: 7.57.2 - resolution: "@microsoft/api-extractor@npm:7.57.2" +"@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" @@ -11263,7 +11263,7 @@ __metadata: typescript: "npm:5.8.2" bin: api-extractor: bin/api-extractor - checksum: 10/7e6ff99a7ee07e34ae4e3d4e271ea794f20ba3b892932e94f3757f230b8f3d6a3f4c18c723c71d3bffdc7a5dd51c732201fc911089cdebae7a4a194d3e4de2e7 + checksum: 10/5b2a8c1833b97db4df49aa0d326b4591474a241da2c71489b5de9f24cc42f7579a2ff45d44bc52302c8f4ffb9dd0fbd6e101f19231003dafd31c0efc8100e2ba languageName: node linkType: hard From 454181703135eb654a9473f449aef6816895a908 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Mon, 23 Feb 2026 06:29:04 -0600 Subject: [PATCH 29/62] Updated API reports due to the package change Signed-off-by: Andre Wanlin --- packages/config-loader/report.api.md | 2 +- packages/core-components/report.api.md | 10 +- packages/core-plugin-api/report.api.md | 2 +- packages/frontend-plugin-api/report.api.md | 8 +- packages/frontend-test-utils/report.api.md | 2 +- packages/theme/report.api.md | 2 +- packages/ui/report.api.md | 31 +--- .../catalog-backend-module-gcp/report.api.md | 13 +- plugins/catalog-react/report-alpha.api.md | 6 +- plugins/devtools/report.api.md | 8 +- plugins/home/report.api.md | 23 +-- plugins/kubernetes-react/report.api.md | 133 +++++------------- plugins/notifications/report.api.md | 17 +-- plugins/scaffolder-common/report.api.md | 7 +- plugins/scaffolder-node/report-alpha.api.md | 19 +-- plugins/techdocs/report.api.md | 28 ++-- 16 files changed, 81 insertions(+), 230 deletions(-) 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/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/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/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-test-utils/report.api.md b/packages/frontend-test-utils/report.api.md index 748eee15d3..d1181f032d 100644 --- a/packages/frontend-test-utils/report.api.md +++ b/packages/frontend-test-utils/report.api.md @@ -275,7 +275,7 @@ export namespace mockApis { // @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/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/report.api.md b/packages/ui/report.api.md index 14283ed1b4..87cea3d387 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -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 { @@ -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/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-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/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/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-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/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/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/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/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; From 8b6b3e1188df3479f7c0b93a37e20eb330a151c6 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Mon, 23 Feb 2026 07:36:12 -0600 Subject: [PATCH 30/62] Added patch Signed-off-by: Andre Wanlin --- .patches/pr-32950.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 .patches/pr-32950.txt diff --git a/.patches/pr-32950.txt b/.patches/pr-32950.txt new file mode 100644 index 0000000000..5b530a0e1c --- /dev/null +++ b/.patches/pr-32950.txt @@ -0,0 +1 @@ +Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` \ No newline at end of file From 2ce812ab3c9810baa46fb3593169ce6e8bcf8c07 Mon Sep 17 00:00:00 2001 From: Andre Wanlin <67169551+awanlin@users.noreply.github.com> Date: Mon, 23 Feb 2026 07:43:46 -0600 Subject: [PATCH 31/62] Update .patches/pr-32950.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Andre Wanlin <67169551+awanlin@users.noreply.github.com> --- .patches/pr-32950.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.patches/pr-32950.txt b/.patches/pr-32950.txt index 5b530a0e1c..4d68055cce 100644 --- a/.patches/pr-32950.txt +++ b/.patches/pr-32950.txt @@ -1 +1 @@ -Updated `@microsoft/api-extractor` to `7.57.3` and added tests for `getTsDocConfig` \ No newline at end of file +Updated `@microsoft/api-extractor` to `7.57.3` \ No newline at end of file From 158bfe8a69aabd5c2ba3182a9db8bd75d158ef14 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 20 Feb 2026 23:36:59 +0100 Subject: [PATCH 32/62] Give each CLI module its own paths instead of importing from lib/ Each module now has a local paths.ts that calls findPaths(__dirname) directly. This makes modules fully independent of lib/paths.ts, and the pattern will continue to work when modules are extracted into separate packages since each package's __dirname will resolve to its own root. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/cli/src/lib/cache/SuccessCache.ts | 5 ++++- packages/cli/src/lib/typeDistProject.ts | 5 ++++- packages/cli/src/lib/version.ts | 5 ++++- packages/cli/src/lib/yarnPlugin.test.ts | 7 ++++--- packages/cli/src/lib/yarnPlugin.ts | 5 ++++- .../build/commands/package/build/command.ts | 2 +- .../build/commands/package/start/command.ts | 2 +- .../commands/package/start/startBackend.ts | 2 +- .../commands/package/start/startFrontend.ts | 2 +- .../src/modules/build/commands/repo/build.ts | 2 +- .../modules/build/commands/repo/start.test.ts | 2 +- .../src/modules/build/commands/repo/start.ts | 2 +- .../src/modules/build/lib/builder/config.ts | 2 +- .../src/modules/build/lib/builder/packager.ts | 2 +- .../src/modules/build/lib/bundler/config.ts | 2 +- .../build/lib/bundler/hasReactDomClient.ts | 2 +- .../build/lib/bundler/linkWorkspaces.ts | 2 +- .../build/lib/bundler/packageDetection.ts | 2 +- .../src/modules/build/lib/bundler/paths.ts | 2 +- .../src/modules/build/lib/bundler/server.ts | 2 +- .../build/lib/packager/createDistWorkspace.ts | 2 +- .../cli/src/modules/build/lib/role.test.ts | 2 +- packages/cli/src/modules/build/lib/role.ts | 2 +- .../modules/build/lib/runner/runBackend.ts | 2 +- .../cli/src/{lib => modules/build}/paths.ts | 0 packages/cli/src/modules/config/lib/config.ts | 2 +- packages/cli/src/modules/config/paths.ts | 20 +++++++++++++++++++ .../commands/create-github-app/index.ts | 2 +- .../src/modules/create-github-app/paths.ts | 20 +++++++++++++++++++ .../cli/src/modules/info/commands/info.ts | 2 +- packages/cli/src/modules/info/paths.ts | 20 +++++++++++++++++++ .../src/modules/lint/commands/package/lint.ts | 2 +- .../src/modules/lint/commands/repo/lint.ts | 2 +- packages/cli/src/modules/lint/paths.ts | 20 +++++++++++++++++++ .../maintenance/commands/package/clean.ts | 2 +- .../maintenance/commands/package/pack.ts | 2 +- .../maintenance/commands/repo/clean.ts | 2 +- .../modules/maintenance/commands/repo/fix.ts | 2 +- .../commands/repo/list-deprecations.ts | 2 +- packages/cli/src/modules/maintenance/paths.ts | 20 +++++++++++++++++++ .../modules/migrate/commands/packageRole.ts | 2 +- .../modules/migrate/commands/versions/bump.ts | 2 +- packages/cli/src/modules/migrate/paths.ts | 20 +++++++++++++++++++ .../modules/new/lib/codeowners/codeowners.ts | 2 +- .../new/lib/execution/PortableTemplater.ts | 2 +- .../new/lib/execution/installNewPackage.ts | 2 +- .../execution/writeTemplateContents.test.ts | 2 +- .../lib/execution/writeTemplateContents.ts | 2 +- .../collectPortableTemplateInput.ts | 2 +- .../lib/preparation/loadPortableTemplate.ts | 2 +- .../preparation/loadPortableTemplateConfig.ts | 2 +- packages/cli/src/modules/new/paths.ts | 20 +++++++++++++++++++ .../src/modules/test/commands/package/test.ts | 2 +- .../src/modules/test/commands/repo/test.ts | 2 +- packages/cli/src/modules/test/paths.ts | 20 +++++++++++++++++++ 55 files changed, 221 insertions(+), 48 deletions(-) rename packages/cli/src/{lib => modules/build}/paths.ts (100%) create mode 100644 packages/cli/src/modules/config/paths.ts create mode 100644 packages/cli/src/modules/create-github-app/paths.ts create mode 100644 packages/cli/src/modules/info/paths.ts create mode 100644 packages/cli/src/modules/lint/paths.ts create mode 100644 packages/cli/src/modules/maintenance/paths.ts create mode 100644 packages/cli/src/modules/migrate/paths.ts create mode 100644 packages/cli/src/modules/new/paths.ts create mode 100644 packages/cli/src/modules/test/paths.ts diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index a799970b4d..0d2f022251 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); const DEFAULT_CACHE_BASE_PATH = 'node_modules/.cache/backstage-cli'; diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index d8469aee37..e8b331d00d 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -20,7 +20,10 @@ 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export const createTypeDistProject = async () => { return new Project({ diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index a7a7ca1bdb..de961e213e 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import semver from 'semver'; -import { paths } from './paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { Lockfile } from './versioning'; /* eslint-disable @backstage/no-relative-monorepo-imports */ diff --git a/packages/cli/src/lib/yarnPlugin.test.ts b/packages/cli/src/lib/yarnPlugin.test.ts index d5c865e1c4..bfc264b74a 100644 --- a/packages/cli/src/lib/yarnPlugin.test.ts +++ b/packages/cli/src/lib/yarnPlugin.test.ts @@ -19,12 +19,13 @@ import { getHasYarnPlugin } from './yarnPlugin'; const mockDir = createMockDirectory(); -jest.mock('./paths', () => ({ - paths: { +jest.mock('@backstage/cli-common', () => ({ + ...jest.requireActual('@backstage/cli-common'), + findPaths: () => ({ resolveTargetRoot(filename: string) { return mockDir.resolve(filename); }, - }, + }), })); describe('getHasYarnPlugin', () => { diff --git a/packages/cli/src/lib/yarnPlugin.ts b/packages/cli/src/lib/yarnPlugin.ts index 5ad49b2524..e73108c463 100644 --- a/packages/cli/src/lib/yarnPlugin.ts +++ b/packages/cli/src/lib/yarnPlugin.ts @@ -17,7 +17,10 @@ import fs from 'fs-extra'; import yaml from 'yaml'; import z from 'zod'; -import { paths } from './paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); const yarnRcSchema = z.object({ plugins: z 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..bf4c5a46f8 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,7 @@ import { PackageGraph, PackageRoles, } from '@backstage/cli-node'; -import { paths } from '../../../../../lib/paths'; +import { paths } from '../../../paths'; import { buildFrontend } from '../../../lib/buildFrontend'; import { buildBackend } from '../../../lib/buildBackend'; import { isValidUrl } from '../../../lib/urls'; 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..5fefb8c03f 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -18,7 +18,7 @@ import { OptionValues } from 'commander'; import { startPackage } from './startPackage'; import { resolveLinkedWorkspace } from './resolveLinkedWorkspace'; import { findRoleFromCommand } from '../../../lib/role'; -import { paths } from '../../../../../lib/paths'; +import { paths } from '../../../paths'; export async function command(opts: OptionValues): Promise { await startPackage({ 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..4b87f0e02a 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,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../../lib/paths'; +import { paths } from '../../../paths'; import { runBackend } from '../../../lib/runner'; interface StartBackendOptions { 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..d55681ea07 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,7 @@ import { getModuleFederationRemoteOptions, serveBundle, } from '../../../../build/lib/bundler'; -import { paths } from '../../../../../lib/paths'; +import { paths } from '../../../paths'; import { BackstagePackageJson } from '@backstage/cli-node'; import { hasReactDomClient } from '../../../../build/lib/bundler/hasReactDomClient'; diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index 6c99ebb0af..c8568be06a 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -18,7 +18,7 @@ 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 { paths } from '../../paths'; import { BackstagePackage, PackageGraph, 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..b1cc9faefd 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -17,7 +17,7 @@ import { PackageGraph } from '@backstage/cli-node'; import { findTargetPackages } from './start'; import { posix } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; const mocks = { app: { diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index bc1ab543c1..e02dfdc6a3 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -20,7 +20,7 @@ import { PackageRole, } from '@backstage/cli-node'; import { relative as relativePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace'; import { startPackage } from '../package/start/startPackage'; import { parseArgs } from 'node:util'; diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 55ae09bf9c..54d33719e0 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -39,7 +39,7 @@ import { import { forwardFileImports, cssEntryPoints } from './plugins'; import { BuildOptions, Output } from './types'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../entryPoints'; diff --git a/packages/cli/src/modules/build/lib/builder/packager.ts b/packages/cli/src/modules/build/lib/builder/packager.ts index 77b1e2b134..16a6ecb828 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -18,7 +18,7 @@ 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 { paths } from '../../paths'; import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; import { PackageRoles, runConcurrentTasks } from '@backstage/cli-node'; diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index a4e2b16ab9..d65fd815c8 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -25,7 +25,7 @@ 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 { paths as cliPaths } from '../../paths'; import fs from 'fs-extra'; import { optimization as optimizationConfig } from './optimization'; import pickBy from 'lodash/pickBy'; diff --git a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts index ad331bdf8b..5e3f4aac49 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; export function hasReactDomClient() { try { diff --git a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts index 39f52067ab..cb3edca684 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 { paths } from '../../paths'; /** * This returns of collection of plugins that links a separate workspace into diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index 47346f803b..48702fcbd9 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 { paths as cliPaths } from '../../paths'; const DETECTED_MODULES_MODULE_NAME = '__backstage-autodetected-plugins__'; diff --git a/packages/cli/src/modules/build/lib/bundler/paths.ts b/packages/cli/src/modules/build/lib/bundler/paths.ts index 3106da5f7d..f7fb6ecdc2 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index b2d480f061..eadbd1b208 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -22,7 +22,7 @@ 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 { paths as libPaths } from '../../paths'; import { loadCliConfig } from '../../../config/lib/config'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 296355e2dd..ca71e0f332 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -24,7 +24,7 @@ import { import { tmpdir } from 'node:os'; import * as tar from 'tar'; import partition from 'lodash/partition'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { run } from '@backstage/cli-common'; import { dependencies as cliDependencies, diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index 89fa533457..ba59dcd8c0 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -20,7 +20,7 @@ import { findRoleFromCommand } from './role'; const mockDir = createMockDirectory(); -jest.mock('../../../lib/paths', () => ({ +jest.mock('../paths', () => ({ paths: { resolveTarget(filename: string) { return mockDir.resolve(filename); diff --git a/packages/cli/src/modules/build/lib/role.ts b/packages/cli/src/modules/build/lib/role.ts index 7af4ccb955..9dc3b55762 100644 --- a/packages/cli/src/modules/build/lib/role.ts +++ b/packages/cli/src/modules/build/lib/role.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../../../lib/paths'; +import { paths } from '../paths'; import { PackageRoles, PackageRole } from '@backstage/cli-node'; export async function findRoleFromCommand( diff --git a/packages/cli/src/modules/build/lib/runner/runBackend.ts b/packages/cli/src/modules/build/lib/runner/runBackend.ts index d8fd447326..511fdd84bb 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -21,7 +21,7 @@ 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 { paths } from '../../paths'; import spawn from 'cross-spawn'; const loaderArgs = [ diff --git a/packages/cli/src/lib/paths.ts b/packages/cli/src/modules/build/paths.ts similarity index 100% rename from packages/cli/src/lib/paths.ts rename to packages/cli/src/modules/build/paths.ts diff --git a/packages/cli/src/modules/config/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts index 2b313f60bd..a8d749f4d1 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -16,7 +16,7 @@ import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { paths } from '../../../lib/paths'; +import { paths } from '../paths'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; diff --git a/packages/cli/src/modules/config/paths.ts b/packages/cli/src/modules/config/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/config/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); 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..e22d14bd6d 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,7 @@ 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 { paths } from '../../paths'; import { GithubCreateAppServer } from './GithubCreateAppServer'; import openBrowser from 'react-dev-utils/openBrowser'; diff --git a/packages/cli/src/modules/create-github-app/paths.ts b/packages/cli/src/modules/create-github-app/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/create-github-app/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/info/commands/info.ts b/packages/cli/src/modules/info/commands/info.ts index 923a02ef4c..d76c8cfc4b 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -17,7 +17,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 { paths } from '../paths'; import { Lockfile } from '../../../lib/versioning'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; import { minimatch } from 'minimatch'; diff --git a/packages/cli/src/modules/info/paths.ts b/packages/cli/src/modules/info/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/info/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/lint/commands/package/lint.ts b/packages/cli/src/modules/lint/commands/package/lint.ts index a1e45c0113..58fa646e48 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 98a100fe3e..c3537ab254 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -25,7 +25,7 @@ import { Lockfile, runWorkerQueueThreads, } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { createScriptOptionsParser } from '../../../../lib/optionsParser'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; diff --git a/packages/cli/src/modules/lint/paths.ts b/packages/cli/src/modules/lint/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/lint/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/maintenance/commands/package/clean.ts b/packages/cli/src/modules/maintenance/commands/package/clean.ts index 5e2d0d65b3..0a2d11bc14 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -15,7 +15,7 @@ */ import fs from 'fs-extra'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; export default async function clean() { await fs.remove(paths.resolveTarget('dist')); diff --git a/packages/cli/src/modules/maintenance/commands/package/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts index cdd50517ae..4c1d475703 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -18,7 +18,7 @@ import { productionPack, revertProductionPack, } from '../../../../modules/build/lib/packager/productionPack'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import fs from 'fs-extra'; import { publishPreflightCheck } from '../../lib/publishing'; import { createTypeDistProject } from '../../../../lib/typeDistProject'; diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index 59e5367837..fc1aabd1b7 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -17,7 +17,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { run } from '@backstage/cli-common'; export async function command(): Promise { diff --git a/packages/cli/src/modules/maintenance/commands/repo/fix.ts b/packages/cli/src/modules/maintenance/commands/repo/fix.ts index a5c6b519ed..4e718a8c9c 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -29,7 +29,7 @@ import { relative as relativePath, extname, } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { publishPreflightCheck } from '../../lib/publishing'; const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx', '.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..37bef58db6 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -19,7 +19,7 @@ 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 { paths } from '../../paths'; export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); diff --git a/packages/cli/src/modules/maintenance/paths.ts b/packages/cli/src/modules/maintenance/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/maintenance/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/migrate/commands/packageRole.ts b/packages/cli/src/modules/migrate/commands/packageRole.ts index 58c1487149..34c20dd6bb 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -18,7 +18,7 @@ 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 { paths } from '../paths'; export default async () => { const { packages } = await getPackages(paths.targetDir); diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index a0a73dd78e..5ca151f162 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -25,7 +25,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 { paths } from '../../paths'; import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; import { fetchPackageInfo, diff --git a/packages/cli/src/modules/migrate/paths.ts b/packages/cli/src/modules/migrate/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/migrate/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index 1cfddabffb..dd03320498 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 { paths } from '../../paths'; const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; diff --git a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts index 9dfd60baba..3662bb13fc 100644 --- a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts +++ b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts @@ -25,7 +25,7 @@ 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 { paths } from '../../paths'; import { createPackageVersionProvider } from '../../../../lib/version'; import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; diff --git a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts index 0fe0284386..fb4a7318c2 100644 --- a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts +++ b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import upperFirst from 'lodash/upperFirst'; import camelCase from 'lodash/camelCase'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { Task } from '../tasks'; import { PortableTemplateInput } from '../types'; 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..7e0e81f137 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,7 @@ import { relative as relativePath } from 'node:path'; import { writeTemplateContents } from './writeTemplateContents'; import { createMockDirectory } from '@backstage/backend-test-utils'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; const baseConfig = { version: '0.1.0', diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index 8b2f9ebf1e..c473632560 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -17,7 +17,7 @@ import fs from 'fs-extra'; import { dirname, resolve as resolvePath } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { PortableTemplate, PortableTemplateInput } from '../types'; import { ForwardedError, InputError } from '@backstage/errors'; import { isMonoRepo as getIsMonoRepo } from '@backstage/cli-node'; diff --git a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts index 38e8eaddba..913e37b88c 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -16,7 +16,7 @@ import inquirer, { DistinctQuestion } from 'inquirer'; import { getCodeownersFilePath, parseOwnerIds } from '../codeowners'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { PortableTemplateConfig, PortableTemplateInput, diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts index f7053df552..d3231cd617 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts @@ -20,7 +20,7 @@ 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 { paths } from '../../paths'; import { PortableTemplateFile, PortableTemplatePointer, diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts index dd937482a2..83b9e387d9 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts @@ -16,7 +16,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath, dirname, isAbsolute } from 'node:path'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { defaultTemplates } from '../defaultTemplates'; import { PortableTemplateConfig, diff --git a/packages/cli/src/modules/new/paths.ts b/packages/cli/src/modules/new/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/new/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/test/commands/package/test.ts b/packages/cli/src/modules/test/commands/package/test.ts index 992697d19c..fa804db20e 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -15,7 +15,7 @@ */ import { Command, OptionValues } from 'commander'; -import { paths } from '../../../../lib/paths'; +import { paths } from '../../paths'; import { runCheck } from '@backstage/cli-common'; function includesAnyOf(hayStack: string[], ...needles: string[]) { diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index f4d488ee0e..6b2ee2b04d 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -23,7 +23,7 @@ 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 { paths } from '../../paths'; import { runCheck, runOutput } from '@backstage/cli-common'; import { isChildPath } from '@backstage/cli-common'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; diff --git a/packages/cli/src/modules/test/paths.ts b/packages/cli/src/modules/test/paths.ts new file mode 100644 index 0000000000..2c658c27b3 --- /dev/null +++ b/packages/cli/src/modules/test/paths.ts @@ -0,0 +1,20 @@ +/* + * 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 { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); From 56bd494b0c87a34c75c09d323b50d04247c7cb01 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 21 Feb 2026 12:43:29 +0100 Subject: [PATCH 33/62] Give each CLI module its own paths instead of importing from lib/ Each module file that needs paths now calls findPaths(__dirname) directly from @backstage/cli-common. This removes the coupling between modules and lib/paths, and will continue to work when modules are extracted into separate packages since each package's __dirname resolves to its own root. Added hierarchical caching to findOwnDir in cli-common so that the filesystem walk only happens once per package - subsequent calls from sibling directories hit the cache at a common ancestor. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-common-cached-paths.md | 5 ++ packages/cli-common/src/paths.ts | 48 ++++++++++++++++--- .../build/commands/package/build/command.ts | 5 +- .../build/commands/package/start/command.ts | 5 +- .../commands/package/start/startBackend.ts | 5 +- .../commands/package/start/startFrontend.ts | 5 +- .../src/modules/build/commands/repo/build.ts | 5 +- .../modules/build/commands/repo/start.test.ts | 5 +- .../src/modules/build/commands/repo/start.ts | 5 +- .../src/modules/build/lib/builder/config.ts | 5 +- .../src/modules/build/lib/builder/packager.ts | 5 +- .../src/modules/build/lib/bundler/config.ts | 7 ++- .../build/lib/bundler/hasReactDomClient.ts | 5 +- .../build/lib/bundler/linkWorkspaces.ts | 5 +- .../build/lib/bundler/packageDetection.ts | 5 +- .../src/modules/build/lib/bundler/paths.ts | 5 +- .../src/modules/build/lib/bundler/server.ts | 5 +- .../build/lib/packager/createDistWorkspace.ts | 7 ++- .../cli/src/modules/build/lib/role.test.ts | 7 +-- packages/cli/src/modules/build/lib/role.ts | 5 +- .../modules/build/lib/runner/runBackend.ts | 5 +- packages/cli/src/modules/build/paths.ts | 20 -------- packages/cli/src/modules/config/lib/config.ts | 5 +- packages/cli/src/modules/config/paths.ts | 20 -------- .../commands/create-github-app/index.ts | 5 +- .../src/modules/create-github-app/paths.ts | 20 -------- .../cli/src/modules/info/commands/info.ts | 7 ++- packages/cli/src/modules/info/paths.ts | 20 -------- .../src/modules/lint/commands/package/lint.ts | 5 +- .../src/modules/lint/commands/repo/lint.ts | 5 +- packages/cli/src/modules/lint/paths.ts | 20 -------- .../maintenance/commands/package/clean.ts | 5 +- .../maintenance/commands/package/pack.ts | 5 +- .../maintenance/commands/repo/clean.ts | 7 ++- .../modules/maintenance/commands/repo/fix.ts | 5 +- .../commands/repo/list-deprecations.ts | 5 +- packages/cli/src/modules/maintenance/paths.ts | 20 -------- .../modules/migrate/commands/packageRole.ts | 5 +- .../modules/migrate/commands/versions/bump.ts | 7 ++- packages/cli/src/modules/migrate/paths.ts | 20 -------- .../modules/new/lib/codeowners/codeowners.ts | 5 +- .../new/lib/execution/PortableTemplater.ts | 5 +- .../new/lib/execution/installNewPackage.ts | 5 +- .../execution/writeTemplateContents.test.ts | 5 +- .../lib/execution/writeTemplateContents.ts | 7 ++- .../collectPortableTemplateInput.ts | 5 +- .../lib/preparation/loadPortableTemplate.ts | 5 +- .../preparation/loadPortableTemplateConfig.ts | 5 +- packages/cli/src/modules/new/paths.ts | 20 -------- .../src/modules/test/commands/package/test.ts | 7 ++- .../src/modules/test/commands/repo/test.ts | 7 ++- packages/cli/src/modules/test/paths.ts | 20 -------- 52 files changed, 219 insertions(+), 237 deletions(-) create mode 100644 .changeset/cli-common-cached-paths.md delete mode 100644 packages/cli/src/modules/build/paths.ts delete mode 100644 packages/cli/src/modules/config/paths.ts delete mode 100644 packages/cli/src/modules/create-github-app/paths.ts delete mode 100644 packages/cli/src/modules/info/paths.ts delete mode 100644 packages/cli/src/modules/lint/paths.ts delete mode 100644 packages/cli/src/modules/maintenance/paths.ts delete mode 100644 packages/cli/src/modules/migrate/paths.ts delete mode 100644 packages/cli/src/modules/new/paths.ts delete mode 100644 packages/cli/src/modules/test/paths.ts diff --git a/.changeset/cli-common-cached-paths.md b/.changeset/cli-common-cached-paths.md new file mode 100644 index 0000000000..27a683e35a --- /dev/null +++ b/.changeset/cli-common-cached-paths.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-common': patch +--- + +Added hierarchical caching to `findOwnDir`, avoiding redundant filesystem walks when `findPaths` is called from multiple locations within the same package. diff --git a/packages/cli-common/src/paths.ts b/packages/cli-common/src/paths.ts index 5da2d596a4..51f7863b99 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -84,15 +84,45 @@ export function findRootPath( ); } +// Hierarchical cache for ownDir lookups. When we resolve a searchDir to its +// package root, we also cache every intermediate directory along the way. This +// means sibling directories only need to walk up until they hit a cached ancestor. +const ownDirCache = new Map(); + // 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}`, - ); + const visited: string[] = []; + let dir = searchDir; + + for (let i = 0; i < 1000; i++) { + const cached = ownDirCache.get(dir); + if (cached !== undefined) { + for (const d of visited) { + ownDirCache.set(d, cached); + } + return cached; + } + + visited.push(dir); + + const packagePath = resolvePath(dir, 'package.json'); + if (fs.existsSync(packagePath)) { + for (const d of visited) { + ownDirCache.set(d, dir); + } + return dir; + } + + const newDir = dirname(dir); + if (newDir === dir) { + break; + } + dir = newDir; } - return path; + + throw new Error( + `No package.json found while searching for package root of ${searchDir}`, + ); } // Finds the root of the monorepo that the package exists in. Only accessible when running inside Backstage repo. @@ -110,6 +140,12 @@ export function findOwnRootDir(ownDir: string) { /** * Find paths related to a package and its execution context. * + * This function is cheap to call repeatedly. The package root lookup is cached + * hierarchically, so calls from different subdirectories within the same package + * only walk the filesystem once. Prefer calling this eagerly at module scope + * rather than sharing a single instance across modules — this keeps modules + * independent and works correctly when they are split into separate packages. + * * @public * @example * 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 bf4c5a46f8..8d2a295dbb 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,10 @@ import { PackageGraph, PackageRoles, } from '@backstage/cli-node'; -import { paths } from '../../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { buildFrontend } from '../../../lib/buildFrontend'; import { buildBackend } from '../../../lib/buildBackend'; import { isValidUrl } from '../../../lib/urls'; 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 5fefb8c03f..3e34ff3bc8 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -18,7 +18,10 @@ import { OptionValues } from 'commander'; import { startPackage } from './startPackage'; import { resolveLinkedWorkspace } from './resolveLinkedWorkspace'; import { findRoleFromCommand } from '../../../lib/role'; -import { paths } from '../../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export async function command(opts: OptionValues): Promise { await startPackage({ 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 4b87f0e02a..9ae2880160 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,10 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { runBackend } from '../../../lib/runner'; interface StartBackendOptions { 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 d55681ea07..b865cea5f4 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,10 @@ import { getModuleFederationRemoteOptions, serveBundle, } from '../../../../build/lib/bundler'; -import { paths } from '../../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { BackstagePackageJson } from '@backstage/cli-node'; import { hasReactDomClient } from '../../../../build/lib/bundler/hasReactDomClient'; diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index c8568be06a..a9a0d51fb9 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -18,7 +18,10 @@ 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { BackstagePackage, PackageGraph, 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 b1cc9faefd..f4a9d2e7eb 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -17,7 +17,10 @@ import { PackageGraph } from '@backstage/cli-node'; import { findTargetPackages } from './start'; import { posix } from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); const mocks = { app: { diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index e02dfdc6a3..46dd95dd3f 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -20,7 +20,10 @@ import { PackageRole, } from '@backstage/cli-node'; import { relative as relativePath } from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace'; import { startPackage } from '../package/start/startPackage'; import { parseArgs } from 'node:util'; diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 54d33719e0..6efb306939 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -39,7 +39,10 @@ import { import { forwardFileImports, cssEntryPoints } from './plugins'; import { BuildOptions, Output } from './types'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../entryPoints'; diff --git a/packages/cli/src/modules/build/lib/builder/packager.ts b/packages/cli/src/modules/build/lib/builder/packager.ts index 16a6ecb828..00b3f93b76 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -18,7 +18,10 @@ 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; import { PackageRoles, runConcurrentTasks } from '@backstage/cli-node'; diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index d65fd815c8..ae180ff2bf 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -25,11 +25,14 @@ 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 '../../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, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const cliPaths = findPaths(__dirname); import { transforms } from './transforms'; import { version } from '../../../../lib/version'; import yn from 'yn'; diff --git a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts index 5e3f4aac49..961d161ced 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export function hasReactDomClient() { try { diff --git a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts index cb3edca684..c9b3e9c0f0 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -17,7 +17,10 @@ import { relative as relativePath } from 'node:path'; import { getPackages } from '@manypkg/get-packages'; import { rspack } from '@rspack/core'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); /** * This returns of collection of plugins that links a separate workspace into diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index 48702fcbd9..1c1eef33e4 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -20,7 +20,10 @@ 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const cliPaths = findPaths(__dirname); const DETECTED_MODULES_MODULE_NAME = '__backstage-autodetected-plugins__'; diff --git a/packages/cli/src/modules/build/lib/bundler/paths.ts b/packages/cli/src/modules/build/lib/bundler/paths.ts index f7fb6ecdc2..9b0c7eaa3a 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index eadbd1b208..3ec20b3e54 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -22,7 +22,10 @@ import openBrowser from 'react-dev-utils/openBrowser'; import { rspack } from '@rspack/core'; import { RspackDevServer } from '@rspack/dev-server'; -import { paths as libPaths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const libPaths = findPaths(__dirname); import { loadCliConfig } from '../../../config/lib/config'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index ca71e0f332..61beba8b0b 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -24,8 +24,11 @@ import { import { tmpdir } from 'node:os'; import * as tar from 'tar'; import partition from 'lodash/partition'; -import { paths } from '../../paths'; -import { run } from '@backstage/cli-common'; + +import { run, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { dependencies as cliDependencies, devDependencies as cliDevDependencies, diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index ba59dcd8c0..a418b42232 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -20,12 +20,13 @@ import { findRoleFromCommand } from './role'; const mockDir = createMockDirectory(); -jest.mock('../paths', () => ({ - paths: { +jest.mock('@backstage/cli-common', () => ({ + ...jest.requireActual('@backstage/cli-common'), + findPaths: () => ({ resolveTarget(filename: string) { return mockDir.resolve(filename); }, - }, + }), })); describe('findRoleFromCommand', () => { diff --git a/packages/cli/src/modules/build/lib/role.ts b/packages/cli/src/modules/build/lib/role.ts index 9dc3b55762..b8de6e5079 100644 --- a/packages/cli/src/modules/build/lib/role.ts +++ b/packages/cli/src/modules/build/lib/role.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { PackageRoles, PackageRole } from '@backstage/cli-node'; export async function findRoleFromCommand( diff --git a/packages/cli/src/modules/build/lib/runner/runBackend.ts b/packages/cli/src/modules/build/lib/runner/runBackend.ts index 511fdd84bb..dea59999be 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -21,7 +21,10 @@ 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import spawn from 'cross-spawn'; const loaderArgs = [ diff --git a/packages/cli/src/modules/build/paths.ts b/packages/cli/src/modules/build/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/build/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/config/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts index a8d749f4d1..0a20cf4705 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -16,7 +16,10 @@ import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { paths } from '../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; diff --git a/packages/cli/src/modules/config/paths.ts b/packages/cli/src/modules/config/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/config/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); 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 e22d14bd6d..d5deab03f5 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,10 @@ import fs from 'fs-extra'; import chalk from 'chalk'; import { stringify as stringifyYaml } from 'yaml'; import inquirer, { Question, Answers } from 'inquirer'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { GithubCreateAppServer } from './GithubCreateAppServer'; import openBrowser from 'react-dev-utils/openBrowser'; diff --git a/packages/cli/src/modules/create-github-app/paths.ts b/packages/cli/src/modules/create-github-app/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/create-github-app/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/info/commands/info.ts b/packages/cli/src/modules/info/commands/info.ts index d76c8cfc4b..3229f5f3ae 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -16,8 +16,11 @@ import { version as cliVersion } from '../../../../package.json'; import os from 'node:os'; -import { runOutput } from '@backstage/cli-common'; -import { paths } from '../paths'; +import { runOutput, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); + import { Lockfile } from '../../../lib/versioning'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; import { minimatch } from 'minimatch'; diff --git a/packages/cli/src/modules/info/paths.ts b/packages/cli/src/modules/info/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/info/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/lint/commands/package/lint.ts b/packages/cli/src/modules/lint/commands/package/lint.ts index 58fa646e48..66e29e8c1f 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index c3537ab254..978119ba73 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -25,7 +25,10 @@ import { Lockfile, runWorkerQueueThreads, } from '@backstage/cli-node'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { createScriptOptionsParser } from '../../../../lib/optionsParser'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; diff --git a/packages/cli/src/modules/lint/paths.ts b/packages/cli/src/modules/lint/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/lint/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/maintenance/commands/package/clean.ts b/packages/cli/src/modules/maintenance/commands/package/clean.ts index 0a2d11bc14..333ab588c2 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -15,7 +15,10 @@ */ import fs from 'fs-extra'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export default async function clean() { await fs.remove(paths.resolveTarget('dist')); diff --git a/packages/cli/src/modules/maintenance/commands/package/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts index 4c1d475703..a4769df785 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -18,7 +18,10 @@ import { productionPack, revertProductionPack, } from '../../../../modules/build/lib/packager/productionPack'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import fs from 'fs-extra'; import { publishPreflightCheck } from '../../lib/publishing'; import { createTypeDistProject } from '../../../../lib/typeDistProject'; diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index fc1aabd1b7..5bebbfd4d8 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -17,8 +17,11 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../paths'; -import { run } from '@backstage/cli-common'; + +import { run, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export async function command(): Promise { const packages = await PackageGraph.listTargetPackages(); diff --git a/packages/cli/src/modules/maintenance/commands/repo/fix.ts b/packages/cli/src/modules/maintenance/commands/repo/fix.ts index 4e718a8c9c..f2d52e2f99 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -29,7 +29,10 @@ import { relative as relativePath, extname, } from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { publishPreflightCheck } from '../../lib/publishing'; const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx', '.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 37bef58db6..0e646c948b 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -19,7 +19,10 @@ import { ESLint } from 'eslint'; import { OptionValues } from 'commander'; import { relative as relativePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); diff --git a/packages/cli/src/modules/maintenance/paths.ts b/packages/cli/src/modules/maintenance/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/maintenance/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/migrate/commands/packageRole.ts b/packages/cli/src/modules/migrate/commands/packageRole.ts index 34c20dd6bb..cc3e1bce69 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -18,7 +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 '../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export default async () => { const { packages } = await getPackages(paths.targetDir); diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index 5ca151f162..8a12683abc 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -13,7 +13,10 @@ * 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, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); bootstrapEnvProxyAgents(); @@ -25,7 +28,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 '../../paths'; + import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; import { fetchPackageInfo, diff --git a/packages/cli/src/modules/migrate/paths.ts b/packages/cli/src/modules/migrate/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/migrate/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index dd03320498..685363bdd3 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import path from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; diff --git a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts index 3662bb13fc..084c9d2d33 100644 --- a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts +++ b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts @@ -25,7 +25,10 @@ import upperCase from 'lodash/upperCase'; import upperFirst from 'lodash/upperFirst'; import lowerFirst from 'lodash/lowerFirst'; import { Lockfile } from '../../../../lib/versioning'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { createPackageVersionProvider } from '../../../../lib/version'; import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; diff --git a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts index fb4a7318c2..7281689ff5 100644 --- a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts +++ b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import upperFirst from 'lodash/upperFirst'; import camelCase from 'lodash/camelCase'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { Task } from '../tasks'; import { PortableTemplateInput } from '../types'; 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 7e0e81f137..2a4cb8a8c5 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); const baseConfig = { version: '0.1.0', diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index c473632560..99e6a1931f 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -17,12 +17,15 @@ import fs from 'fs-extra'; import { dirname, resolve as resolvePath } from 'node:path'; -import { paths } from '../../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, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); export async function writeTemplateContents( template: PortableTemplate, diff --git a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts index 913e37b88c..7a6046f927 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -16,7 +16,10 @@ import inquirer, { DistinctQuestion } from 'inquirer'; import { getCodeownersFilePath, parseOwnerIds } from '../codeowners'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { PortableTemplateConfig, PortableTemplateInput, diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts index d3231cd617..8b77296249 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts @@ -20,7 +20,10 @@ 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 '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { PortableTemplateFile, PortableTemplatePointer, diff --git a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts index 83b9e387d9..61e04a20a5 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts @@ -16,7 +16,10 @@ import fs from 'fs-extra'; import { resolve as resolvePath, dirname, isAbsolute } from 'node:path'; -import { paths } from '../../paths'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { defaultTemplates } from '../defaultTemplates'; import { PortableTemplateConfig, diff --git a/packages/cli/src/modules/new/paths.ts b/packages/cli/src/modules/new/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/new/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); diff --git a/packages/cli/src/modules/test/commands/package/test.ts b/packages/cli/src/modules/test/commands/package/test.ts index fa804db20e..e425af4962 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -15,8 +15,11 @@ */ import { Command, OptionValues } from 'commander'; -import { paths } from '../../paths'; -import { runCheck } from '@backstage/cli-common'; + +import { runCheck, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); function includesAnyOf(hayStack: string[], ...needles: string[]) { for (const needle of needles) { diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index 6b2ee2b04d..717f15e788 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -23,8 +23,11 @@ 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 '../../paths'; -import { runCheck, runOutput } from '@backstage/cli-common'; + +import { runCheck, runOutput, findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const paths = findPaths(__dirname); import { isChildPath } from '@backstage/cli-common'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; diff --git a/packages/cli/src/modules/test/paths.ts b/packages/cli/src/modules/test/paths.ts deleted file mode 100644 index 2c658c27b3..0000000000 --- a/packages/cli/src/modules/test/paths.ts +++ /dev/null @@ -1,20 +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 { findPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); From 29e91e9159dae1a83456d35958651a1fd9aa42a0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 21 Feb 2026 13:16:50 +0100 Subject: [PATCH 34/62] Give each CLI module its own paths instead of importing from lib/ Split the paths API in @backstage/cli-common into targetPaths (a lazily initialized singleton for cwd-based paths) and findOwnPaths (a cached function for package-relative paths). Most CLI module files only need target paths, which can now be imported directly without __dirname. The few files that need own paths use findOwnPaths(__dirname). Added hierarchical caching to findOwnDir so the filesystem walk only happens once per package. targetPaths re-resolves automatically if process.cwd() changes. The deprecated findPaths function is preserved for backward compatibility, delegating to the new primitives internally. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- packages/backend/package.json | 4 +- packages/backend/src/index.ts | 2 +- packages/cli-common/src/index.ts | 4 +- packages/cli-common/src/paths.ts | 220 +++++++++++++----- packages/cli/src/lib/cache/SuccessCache.ts | 6 +- packages/cli/src/lib/typeDistProject.ts | 6 +- packages/cli/src/lib/version.ts | 9 +- packages/cli/src/lib/yarnPlugin.test.ts | 4 +- packages/cli/src/lib/yarnPlugin.ts | 6 +- .../build/commands/package/build/command.ts | 14 +- .../build/commands/package/start/command.ts | 6 +- .../commands/package/start/startBackend.ts | 6 +- .../commands/package/start/startFrontend.ts | 8 +- .../src/modules/build/commands/repo/build.ts | 6 +- .../modules/build/commands/repo/start.test.ts | 6 +- .../src/modules/build/commands/repo/start.ts | 8 +- .../src/modules/build/lib/builder/config.ts | 10 +- .../src/modules/build/lib/builder/packager.ts | 14 +- .../src/modules/build/lib/bundler/config.ts | 6 +- .../build/lib/bundler/hasReactDomClient.ts | 6 +- .../build/lib/bundler/linkWorkspaces.ts | 6 +- .../build/lib/bundler/packageDetection.ts | 6 +- .../src/modules/build/lib/bundler/paths.ts | 17 +- .../src/modules/build/lib/bundler/server.ts | 8 +- .../build/lib/packager/createDistWorkspace.ts | 14 +- .../cli/src/modules/build/lib/role.test.ts | 4 +- packages/cli/src/modules/build/lib/role.ts | 6 +- .../modules/build/lib/runner/runBackend.ts | 6 +- packages/cli/src/modules/config/lib/config.ts | 10 +- .../commands/create-github-app/index.ts | 6 +- .../cli/src/modules/info/commands/info.ts | 13 +- .../src/modules/lint/commands/package/lint.ts | 10 +- .../src/modules/lint/commands/repo/lint.ts | 14 +- .../maintenance/commands/package/clean.ts | 10 +- .../maintenance/commands/package/pack.ts | 12 +- .../maintenance/commands/repo/clean.ts | 10 +- .../modules/maintenance/commands/repo/fix.ts | 16 +- .../commands/repo/list-deprecations.ts | 10 +- .../modules/migrate/commands/packageRole.ts | 6 +- .../migrate/commands/versions/bump.test.ts | 10 +- .../modules/migrate/commands/versions/bump.ts | 10 +- .../migrate/commands/versions/migrate.test.ts | 10 +- .../modules/new/lib/codeowners/codeowners.ts | 6 +- .../new/lib/execution/PortableTemplater.ts | 6 +- .../new/lib/execution/installNewPackage.ts | 10 +- .../execution/writeTemplateContents.test.ts | 6 +- .../lib/execution/writeTemplateContents.ts | 6 +- .../collectPortableTemplateInput.ts | 6 +- .../lib/preparation/loadPortableTemplate.ts | 6 +- .../preparation/loadPortableTemplateConfig.ts | 6 +- .../src/modules/test/commands/package/test.ts | 7 +- .../src/modules/test/commands/repo/test.ts | 11 +- 52 files changed, 332 insertions(+), 303 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index b6b97f214e..23b7c17417 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -61,7 +61,6 @@ "@backstage/plugin-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", "@backstage/plugin-search-backend-module-elasticsearch": "workspace:^", - "@backstage/plugin-search-backend-module-explore": "workspace:^", "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-signals-backend": "workspace:^", @@ -69,7 +68,8 @@ "@opentelemetry/auto-instrumentations-node": "^0.67.0", "@opentelemetry/exporter-prometheus": "^0.211.0", "@opentelemetry/sdk-node": "^0.211.0", - "example-app": "link:../app" + "example-app": "link:../app", + "@backstage-community/plugin-search-backend-module-explore": "workspace:^" }, "devDependencies": { "@backstage/cli": "workspace:^" diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 14eb36a3a6..9c42c6b740 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -32,7 +32,7 @@ const searchLoader = createBackendFeatureLoader({ *loader({ config }) { yield import('@backstage/plugin-search-backend'); yield import('@backstage/plugin-search-backend-module-catalog'); - yield import('@backstage/plugin-search-backend-module-explore'); + yield import('@backstage-community/plugin-search-backend-module-explore'); yield import('@backstage/plugin-search-backend-module-techdocs'); if (config.has('search.elasticsearch')) { yield import('@backstage/plugin-search-backend-module-elasticsearch'); 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 51f7863b99..c0e80b24f6 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -26,30 +26,20 @@ import { dirname, resolve as resolvePath } from 'node:path'; export type ResolveFunc = (...paths: string[]) => string; /** - * Common paths and resolve functions used by the cli. - * Currently assumes it is being executed within a monorepo. + * Paths relative to the target project that the CLI is operating on, based on + * `process.cwd()`. This can be imported directly — no `__dirname` needed. + * + * Lazily initialized on first access and re-resolved if `process.cwd()` changes. * * @public */ -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; - +export type TargetPaths = { // 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; @@ -57,6 +47,44 @@ export type Paths = { resolveTargetRoot: ResolveFunc; }; +/** + * Paths relative to the package that the calling code lives in. Requires + * `__dirname` to locate the package root. + * + * @public + */ +export type OwnPaths = { + // Root dir of the package itself, containing package.json + ownDir: string; + + // Monorepo root dir of the package. Only accessible when running inside Backstage repo. + ownRoot: string; + + // Resolve a path relative to own package + resolveOwn: ResolveFunc; + + // Resolve a path relative to own monorepo root. Only accessible when running inside Backstage repo. + resolveOwnRoot: 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 = { + ownDir: string; + ownRoot: string; + targetDir: string; + targetRoot: string; + resolveOwn: ResolveFunc; + resolveOwnRoot: ResolveFunc; + resolveTarget: ResolveFunc; + resolveTargetRoot: ResolveFunc; +}; + // Looks for a package.json with a workspace config to identify the root of the monorepo export function findRootPath( searchDir: string, @@ -137,28 +165,95 @@ export function findOwnRootDir(ownDir: string) { return resolvePath(ownDir, '../..'); } +// Cached target path state. Re-resolves when process.cwd() changes. +let cachedTargetCwd: string | undefined; +let cachedTargetDir: string | undefined; +let cachedTargetRoot: string | undefined; + +function getTargetDir(): string { + const cwd = process.cwd(); + if (cachedTargetDir !== undefined && cachedTargetCwd === cwd) { + return cachedTargetDir; + } + cachedTargetCwd = cwd; + cachedTargetRoot = undefined; + // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency + cachedTargetDir = fs + .realpathSync(cwd) + .replace(/^[a-z]:/, str => str.toLocaleUpperCase('en-US')); + return cachedTargetDir; +} + +function getTargetRoot(): string { + // Ensure targetDir is fresh, which also invalidates targetRoot on cwd change + const targetDir = getTargetDir(); + if (cachedTargetRoot !== undefined) { + return cachedTargetRoot; + } + // 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. + cachedTargetRoot = + 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; + return cachedTargetRoot; +} + /** - * Find paths related to a package and its execution context. + * Lazily resolved paths relative to the target project. Import this directly + * for cwd-based path resolution without needing `__dirname`. * - * This function is cheap to call repeatedly. The package root lookup is cached - * hierarchically, so calls from different subdirectories within the same package - * only walk the filesystem once. Prefer calling this eagerly at module scope - * rather than sharing a single instance across modules — this keeps modules - * independent and works correctly when they are split into separate packages. + * Re-resolves automatically if `process.cwd()` changes. * * @public * @example * - * const paths = findPaths(__dirname) + * import { targetPaths } from '@backstage/cli-common'; + * + * const root = targetPaths.targetRoot; + * const lockfile = targetPaths.resolveTargetRoot('yarn.lock'); */ -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')); +export const targetPaths: TargetPaths = { + get targetDir() { + return getTargetDir(); + }, + get targetRoot() { + return getTargetRoot(); + }, + resolveTarget: (...paths) => resolvePath(getTargetDir(), ...paths), + resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), +}; + +const ownPathsCache = new Map(); + +/** + * Find paths relative to the package that the calling code lives in. Cheap to + * call repeatedly — results are cached per package root, and the package root + * lookup uses a hierarchical cache so sibling directories share work. + * + * @public + * @example + * + * import { findOwnPaths } from '@backstage/cli-common'; + * + * const ownPaths = findOwnPaths(__dirname); + * const config = ownPaths.resolveOwn('config/jest.js'); + */ +export function findOwnPaths(searchDir: string): OwnPaths { + const ownDir = findOwnDir(searchDir); + const cached = ownPathsCache.get(ownDir); + if (cached) { + return cached; + } - // Lazy load this as it will throw an error if we're not inside the Backstage repo. let ownRoot = ''; const getOwnRoot = () => { if (!ownRoot) { @@ -167,40 +262,49 @@ export function findPaths(searchDir: string): Paths { 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; - }; - - return { + const paths: OwnPaths = { ownDir, get ownRoot() { return getOwnRoot(); }, - targetDir, - get targetRoot() { - return getTargetRoot(); + resolveOwn: (...p) => resolvePath(ownDir, ...p), + resolveOwnRoot: (...p) => resolvePath(getOwnRoot(), ...p), + }; + + ownPathsCache.set(ownDir, paths); + return paths; +} + +/** + * 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 own = findOwnPaths(searchDir); + return { + get ownDir() { + return own.ownDir; }, - resolveOwn: (...paths) => resolvePath(ownDir, ...paths), - resolveOwnRoot: (...paths) => resolvePath(getOwnRoot(), ...paths), - resolveTarget: (...paths) => resolvePath(targetDir, ...paths), - resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), + get ownRoot() { + return own.ownRoot; + }, + get targetDir() { + return targetPaths.targetDir; + }, + get targetRoot() { + return targetPaths.targetRoot; + }, + resolveOwn: own.resolveOwn, + resolveOwnRoot: own.resolveOwnRoot, + resolveTarget: targetPaths.resolveTarget, + resolveTargetRoot: targetPaths.resolveTargetRoot, }; } diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index 0d2f022251..bf7436ed62 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); const DEFAULT_CACHE_BASE_PATH = 'node_modules/.cache/backstage-cli'; @@ -34,7 +32,7 @@ export class SuccessCache { * location. */ static trimPaths(input: string) { - return input.replaceAll(paths.targetRoot, ''); + return input.replaceAll(targetPaths.targetRoot, ''); } constructor(name: string, basePath?: string) { diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index e8b331d00d..161ea2be82 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -20,14 +20,12 @@ import { } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; import { Project, SourceFile, SyntaxKind, ts, Type } from 'ts-morph'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export const createTypeDistProject = async () => { return new Project({ - tsConfigFilePath: paths.resolveTargetRoot('tsconfig.json'), + tsConfigFilePath: targetPaths.resolveTargetRoot('tsconfig.json'), skipAddingFilesFromTsConfig: true, }); }; diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index de961e213e..326657a9b0 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -16,10 +16,9 @@ import fs from 'fs-extra'; import semver from 'semver'; -import { findPaths } from '@backstage/cli-common'; +import { findOwnPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); +const ownPaths = findOwnPaths(__dirname); import { Lockfile } from './versioning'; /* eslint-disable @backstage/no-relative-monorepo-imports */ @@ -85,12 +84,12 @@ export const packageVersions: Record = { }; export function findVersion() { - const pkgContent = fs.readFileSync(paths.resolveOwn('package.json'), 'utf8'); + const pkgContent = fs.readFileSync(ownPaths.resolveOwn('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.resolveOwn('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 bfc264b74a..ac9345a4a4 100644 --- a/packages/cli/src/lib/yarnPlugin.test.ts +++ b/packages/cli/src/lib/yarnPlugin.test.ts @@ -21,11 +21,11 @@ const mockDir = createMockDirectory(); jest.mock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), - findPaths: () => ({ + targetPaths: { resolveTargetRoot(filename: string) { return mockDir.resolve(filename); }, - }), + }, })); describe('getHasYarnPlugin', () => { diff --git a/packages/cli/src/lib/yarnPlugin.ts b/packages/cli/src/lib/yarnPlugin.ts index e73108c463..b8c56b98ec 100644 --- a/packages/cli/src/lib/yarnPlugin.ts +++ b/packages/cli/src/lib/yarnPlugin.ts @@ -17,10 +17,8 @@ import fs from 'fs-extra'; import yaml from 'yaml'; import z from 'zod'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); const yarnRcSchema = z.object({ plugins: z @@ -38,7 +36,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.resolveTargetRoot('.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 8d2a295dbb..6a04524d17 100644 --- a/packages/cli/src/modules/build/commands/package/build/command.ts +++ b/packages/cli/src/modules/build/commands/package/build/command.ts @@ -23,10 +23,8 @@ import { PackageGraph, PackageRoles, } from '@backstage/cli-node'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { buildFrontend } from '../../../lib/buildFrontend'; import { buildBackend } from '../../../lib/buildBackend'; import { isValidUrl } from '../../../lib/urls'; @@ -44,19 +42,19 @@ export async function command(opts: OptionValues): Promise { if (isValidUrl(arg)) { return arg; } - return paths.resolveTarget(arg); + return targetPaths.resolveTarget(arg); }); if (role === 'frontend') { return buildFrontend({ - targetDir: paths.targetDir, + targetDir: targetPaths.targetDir, configPaths, writeStats: Boolean(opts.stats), webpack, }); } return buildBackend({ - targetDir: paths.targetDir, + targetDir: targetPaths.targetDir, configPaths, skipBuildDependencies: Boolean(opts.skipBuildDependencies), minify: Boolean(opts.minify), @@ -79,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.targetDir, configPaths: [], writeStats: Boolean(opts.stats), isModuleFederationRemote, @@ -102,7 +100,7 @@ export async function command(opts: OptionValues): Promise { } const packageJson = (await fs.readJson( - paths.resolveTarget('package.json'), + targetPaths.resolveTarget('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 3e34ff3bc8..fb9f10deac 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -18,16 +18,14 @@ import { OptionValues } from 'commander'; import { startPackage } from './startPackage'; import { resolveLinkedWorkspace } from './resolveLinkedWorkspace'; import { findRoleFromCommand } from '../../../lib/role'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export async function command(opts: OptionValues): Promise { await startPackage({ role: await findRoleFromCommand(opts), entrypoint: opts.entrypoint, - targetDir: paths.targetDir, + targetDir: targetPaths.targetDir, 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 9ae2880160..7a593bb7d7 100644 --- a/packages/cli/src/modules/build/commands/package/start/startBackend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startBackend.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { runBackend } from '../../../lib/runner'; interface StartBackendOptions { @@ -46,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.targetDir, '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 b865cea5f4..60b4fab14d 100644 --- a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts @@ -20,10 +20,8 @@ import { getModuleFederationRemoteOptions, serveBundle, } from '../../../../build/lib/bundler'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { BackstagePackageJson } from '@backstage/cli-node'; import { hasReactDomClient } from '../../../../build/lib/bundler/hasReactDomClient'; @@ -41,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.targetDir, 'package.json'), )) as BackstagePackageJson; if (!hasReactDomClient()) { @@ -61,7 +59,7 @@ export async function startFrontend(options: StartAppOptions) { moduleFederationRemote: options.isModuleFederationRemote ? await getModuleFederationRemoteOptions( packageJson, - resolvePath(paths.targetDir), + resolvePath(targetPaths.targetDir), ) : undefined, }); diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index a9a0d51fb9..22530875f5 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -18,10 +18,8 @@ import chalk from 'chalk'; import { Command, OptionValues } from 'commander'; import { relative as relativePath } from 'node:path'; import { buildPackages, getOutputsForRole } from '../../lib/builder'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { BackstagePackage, PackageGraph, @@ -92,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.targetRoot, pkg.dir))}: `, workspacePackages: packages, minify: opts.minify ?? buildOptions.minify, }; 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 f4a9d2e7eb..cc9e5cd8ec 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -17,10 +17,8 @@ import { PackageGraph } from '@backstage/cli-node'; import { findTargetPackages } from './start'; import { posix } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); const mocks = { app: { @@ -101,7 +99,7 @@ describe('findTargetPackages', () => { beforeEach(() => { jest.clearAllMocks(); jest - .spyOn(paths, 'resolveTargetRoot') + .spyOn(targetPaths, 'resolveTargetRoot') .mockImplementation((...parts: string[]) => { return posix.resolve('/root', ...parts); }); diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index 46dd95dd3f..cd45c7941e 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -20,10 +20,8 @@ import { PackageRole, } from '@backstage/cli-node'; import { relative as relativePath } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace'; import { startPackage } from '../package/start/startPackage'; import { parseArgs } from 'node:util'; @@ -98,7 +96,7 @@ export async function findTargetPackages( pkg => nameOrPath === pkg.packageJson.name, ); if (!matchingPackage) { - const absPath = paths.resolveTargetRoot(nameOrPath); + const absPath = targetPaths.resolveTargetRoot(nameOrPath); matchingPackage = packages.find( pkg => relativePath(pkg.dir, absPath) === '', ); @@ -120,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.resolveTargetRoot( role === 'frontend' ? 'packages/app' : 'packages/backend', ); const matchByPath = matchingPackages.find( diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 6efb306939..ba8028f2d6 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -39,10 +39,8 @@ import { import { forwardFileImports, cssEntryPoints } from './plugins'; import { BuildOptions, Output } from './types'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { BackstagePackageJson } from '@backstage/cli-node'; import { readEntryPoints } from '../entryPoints'; @@ -119,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.targetDir; let targetPkg = options.packageJson; if (!targetPkg) { @@ -287,9 +285,9 @@ export async function makeRollupConfigs( const input = Object.fromEntries( scriptEntryPoints.map(e => [ e.name, - paths.resolveTargetRoot( + targetPaths.resolveTargetRoot( 'dist-types', - relativePath(paths.targetRoot, targetDir), + relativePath(targetPaths.targetRoot, 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 00b3f93b76..e1a10b3ac8 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -18,10 +18,8 @@ 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 { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { makeRollupConfigs } from './config'; import { BuildOptions, Output } from './types'; import { PackageRoles, runConcurrentTasks } from '@backstage/cli-node'; @@ -36,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.targetDir, error.id); const loc = chalk.cyan(`${path}:${line}:${column}`); if (text === 'Unexpected "<"' && error.id.endsWith('.js')) { @@ -55,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.resolveTarget((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.resolveTarget(error.id)}\n`; } msg += `${error}\n`; @@ -92,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.resolveTargetRoot('package.json'), ); if (resolutions?.esbuild) { console.warn( @@ -109,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.targetDir; await fs.remove(resolvePath(targetDir, 'dist')); const buildTasks = rollupConfigs.map(rollupBuild); diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index ae180ff2bf..c0537bb36c 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -29,10 +29,8 @@ import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack'; import fs from 'fs-extra'; import { optimization as optimizationConfig } from './optimization'; import pickBy from 'lodash/pickBy'; -import { runOutput, findPaths } from '@backstage/cli-common'; +import { runOutput, targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const cliPaths = findPaths(__dirname); import { transforms } from './transforms'; import { version } from '../../../../lib/version'; import yn from 'yn'; @@ -99,7 +97,7 @@ async function readBuildInfo() { } const { version: packageVersion } = await fs.readJson( - cliPaths.resolveTarget('package.json'), + targetPaths.resolveTarget('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 961d161ced..ab48599033 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -14,15 +14,13 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export function hasReactDomClient() { try { require.resolve('react-dom/client', { - paths: [paths.targetDir], + paths: [targetPaths.targetDir], }); 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 c9b3e9c0f0..6976df99a5 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -17,10 +17,8 @@ import { relative as relativePath } from 'node:path'; import { getPackages } from '@manypkg/get-packages'; import { rspack } from '@rspack/core'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); /** * This returns of collection of plugins that links a separate workspace into @@ -55,7 +53,7 @@ export async function createWorkspaceLinkingPlugins( /^react(?:-router)?(?:-dom)?$/, resource => { if (!relativePath(linkedRoot.dir, resource.context).startsWith('..')) { - resource.context = paths.targetDir; + resource.context = targetPaths.targetDir; } }, ), diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index 1c1eef33e4..e0a3069733 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -20,10 +20,8 @@ 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 { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const cliPaths = findPaths(__dirname); const DETECTED_MODULES_MODULE_NAME = '__backstage-autodetected-plugins__'; @@ -149,7 +147,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.targetRoot, '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 9b0c7eaa3a..166fc20d5b 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -16,22 +16,21 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths, findOwnPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); +const ownPaths = findOwnPaths(__dirname); export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' entry: string; - // Target directory, defaulting to paths.targetDir + // Target directory, defaulting to targetPaths.targetDir 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.targetDir } = options; const resolveTargetModule = (pathString: string) => { for (const ext of ['mjs', 'js', 'ts', 'tsx', 'jsx']) { @@ -52,7 +51,7 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { } else { targetHtml = resolvePath(targetDir, `${entry}.html`); if (!fs.pathExistsSync(targetHtml)) { - targetHtml = paths.resolveOwn('templates/serve_index.html'); + targetHtml = ownPaths.resolveOwn('templates/serve_index.html'); } } @@ -70,10 +69,10 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetSrc: resolvePath(targetDir, 'src'), targetDev: resolvePath(targetDir, 'dev'), targetEntry: resolveTargetModule(entry), - targetTsConfig: paths.resolveTargetRoot('tsconfig.json'), + targetTsConfig: targetPaths.resolveTargetRoot('tsconfig.json'), targetPackageJson: resolvePath(targetDir, 'package.json'), - rootNodeModules: paths.resolveTargetRoot('node_modules'), - root: paths.targetRoot, + rootNodeModules: targetPaths.resolveTargetRoot('node_modules'), + root: targetPaths.targetRoot, }; } diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index 3ec20b3e54..f729a0a084 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -22,10 +22,8 @@ import openBrowser from 'react-dev-utils/openBrowser'; import { rspack } from '@rspack/core'; import { RspackDevServer } from '@rspack/dev-server'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const libPaths = findPaths(__dirname); import { loadCliConfig } from '../../../config/lib/config'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; @@ -56,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.targetDir, 'package.json'), ); let devServer: RspackDevServer | undefined = undefined; @@ -274,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.targetRoot], }); const reactPkg = require(reactPkgPath); if (reactPkg.version.startsWith('16.')) { diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 61beba8b0b..0312108c88 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -25,10 +25,8 @@ import { tmpdir } from 'node:os'; import * as tar from 'tar'; import partition from 'lodash/partition'; -import { run, findPaths } from '@backstage/cli-common'; +import { run, targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { dependencies as cliDependencies, devDependencies as cliDevDependencies, @@ -213,7 +211,7 @@ 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.targetRoot, pkg.dir))}: `, minify: options.minify, workspacePackages: packages, }); @@ -248,13 +246,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.resolveTargetRoot(src), resolvePath(targetDir, dest)); } if (options.skeleton) { const skeletonFiles = targets .map(target => { - const dir = relativePath(paths.targetRoot, target.dir); + const dir = relativePath(targetPaths.targetRoot, target.dir); return joinPath(dir, 'package.json'); }) .sort(); @@ -303,7 +301,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.targetRoot, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await productionPack({ packageDir: target.dir, @@ -323,7 +321,7 @@ async function moveToDistWorkspace( cwd: target.dir, }).waitForExit(); - const outputDir = relativePath(paths.targetRoot, target.dir); + const outputDir = relativePath(targetPaths.targetRoot, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await fs.ensureDir(absoluteOutputPath); diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index a418b42232..83372e010f 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -22,11 +22,11 @@ const mockDir = createMockDirectory(); jest.mock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), - findPaths: () => ({ + targetPaths: { resolveTarget(filename: string) { return mockDir.resolve(filename); }, - }), + }, })); describe('findRoleFromCommand', () => { diff --git a/packages/cli/src/modules/build/lib/role.ts b/packages/cli/src/modules/build/lib/role.ts index b8de6e5079..95ef580048 100644 --- a/packages/cli/src/modules/build/lib/role.ts +++ b/packages/cli/src/modules/build/lib/role.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { PackageRoles, PackageRole } from '@backstage/cli-node'; export async function findRoleFromCommand( @@ -29,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.resolveTarget('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 dea59999be..2291395246 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -21,10 +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 { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import spawn from 'cross-spawn'; const loaderArgs = [ @@ -138,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.resolveTargetRoot('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 0a20cf4705..da212e9269 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -16,10 +16,8 @@ import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; import { resolve as resolvePath } from 'node:path'; @@ -37,7 +35,7 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const targetDir = options.targetDir ?? paths.targetDir; + const targetDir = options.targetDir ?? targetPaths.targetDir; // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(targetDir); @@ -66,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.resolveTargetRoot('package.json')], noUndeclaredProperties: options.strict, }); @@ -76,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.targetRoot, 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 d5deab03f5..61f7f43cab 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,10 +18,8 @@ import fs from 'fs-extra'; import chalk from 'chalk'; import { stringify as stringifyYaml } from 'yaml'; import inquirer, { Question, Answers } from 'inquirer'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { GithubCreateAppServer } from './GithubCreateAppServer'; import openBrowser from 'react-dev-utils/openBrowser'; @@ -65,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.resolveTargetRoot(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 3229f5f3ae..f74529f7ae 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -16,10 +16,9 @@ import { version as cliVersion } from '../../../../package.json'; import os from 'node:os'; -import { runOutput, findPaths } from '@backstage/cli-common'; +import { runOutput, targetPaths, findOwnPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); +const ownPaths = findOwnPaths(__dirname); import { Lockfile } from '../../../lib/versioning'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; @@ -59,9 +58,9 @@ 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')); + const isLocal = fs.existsSync(ownPaths.resolveOwn('./src')); - const backstageFile = paths.resolveTargetRoot('backstage.json'); + const backstageFile = targetPaths.resolveTargetRoot('backstage.json'); let backstageVersion = 'N/A'; if (fs.existsSync(backstageFile)) { try { @@ -86,9 +85,9 @@ export default async (options: InfoOptions) => { backstage: backstageVersion, }; - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveTargetRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); - const targetPath = paths.targetRoot; + const targetPath = targetPaths.targetRoot; // 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 66e29e8c1f..e5d706373a 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -16,15 +16,13 @@ import fs from 'fs-extra'; import { OptionValues } from 'commander'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { const eslint = new ESLint({ - cwd: paths.targetDir, + cwd: targetPaths.targetDir, fix: opts.fix, extensions: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'], }); @@ -50,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.targetRoot); } const resultText = await formatter.format(results); if (resultText) { if (opts.outputFile) { - await fs.writeFile(paths.resolveTarget(opts.outputFile), resultText); + await fs.writeFile(targetPaths.resolveTarget(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 978119ba73..67ba77fcca 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -25,10 +25,8 @@ import { Lockfile, runWorkerQueueThreads, } from '@backstage/cli-node'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { createScriptOptionsParser } from '../../../../lib/optionsParser'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; @@ -47,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.resolveTargetRoot('yarn.lock')), } : undefined; @@ -65,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.targetRoot); } // Make sure lint output is colored unless the user explicitly disabled it @@ -80,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.targetRoot, pkg.dir), lintOptions, parentHash: undefined, }; @@ -116,7 +114,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { shouldCache: Boolean(cacheContext), maxWarnings: opts.maxWarnings ?? -1, successCache: cacheContext?.entries, - rootDir: paths.targetRoot, + rootDir: targetPaths.targetRoot, }, workerFactory: async ({ fix, @@ -266,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.resolveTargetRoot(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 333ab588c2..bebf5c6ec1 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -15,13 +15,11 @@ */ import fs from 'fs-extra'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); 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.resolveTarget('dist')); + await fs.remove(targetPaths.resolveTarget('dist-types')); + await fs.remove(targetPaths.resolveTarget('coverage')); } diff --git a/packages/cli/src/modules/maintenance/commands/package/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts index a4769df785..bd1e93cf5d 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -18,26 +18,24 @@ import { productionPack, revertProductionPack, } from '../../../../modules/build/lib/packager/productionPack'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); 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.targetDir, + packageJson: await fs.readJson(targetPaths.resolveTarget('package.json')), }); await productionPack({ - packageDir: paths.targetDir, + packageDir: targetPaths.targetDir, featureDetectionProject: await createTypeDistProject(), }); }; export const post = async () => { - await revertProductionPack(paths.targetDir); + await revertProductionPack(targetPaths.targetDir); }; diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index 5bebbfd4d8..490f6a850e 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -18,17 +18,15 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { run, findPaths } from '@backstage/cli-common'; +import { run, targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); 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.resolveTargetRoot('dist')); + await fs.remove(targetPaths.resolveTargetRoot('dist-types')); + await fs.remove(targetPaths.resolveTargetRoot('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 f2d52e2f99..63ade707ef 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -29,10 +29,8 @@ import { relative as relativePath, extname, } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { publishPreflightCheck } from '../../lib/publishing'; const SCRIPT_EXTS = ['.js', '.jsx', '.ts', '.tsx', '.json']; @@ -52,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.resolveTargetRoot('package.json')); const fixCmd = rootPkg.scripts?.fix === 'backstage-cli repo fix' ? 'fix' @@ -219,7 +217,7 @@ export function fixSideEffects(pkg: FixablePackage) { } export function createRepositoryFieldFixer() { - const rootPkg = require(paths.resolveTargetRoot('package.json')); + const rootPkg = require(targetPaths.resolveTargetRoot('package.json')); const rootRepoField = rootPkg.repository; if (!rootRepoField) { return () => {}; @@ -232,7 +230,7 @@ export function createRepositoryFieldFixer() { return (pkg: FixablePackage) => { const expectedPath = posix.join( rootDir, - relativePath(paths.targetRoot, pkg.dir), + relativePath(targetPaths.targetRoot, pkg.dir), ); const repoField = pkg.packageJson.repository; @@ -321,7 +319,7 @@ export function fixPluginId(pkg: FixablePackage) { role === 'backend-plugin-module') ) { const path = relativePath( - paths.targetRoot, + targetPaths.targetRoot, 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}"`; @@ -417,7 +415,7 @@ export function fixPluginPackages( return; } const path = relativePath( - paths.targetRoot, + targetPaths.targetRoot, resolvePath(pkg.dir, 'package.json'), ); const suggestedRole = @@ -466,7 +464,7 @@ export function fixPeerModules(pkg: FixablePackage) { } const packagePath = relativePath( - paths.targetRoot, + targetPaths.targetRoot, 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 0e646c948b..1444d1062e 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -19,23 +19,21 @@ import { ESLint } from 'eslint'; import { OptionValues } from 'commander'; import { relative as relativePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); const eslint = new ESLint({ - cwd: paths.targetDir, + cwd: targetPaths.targetDir, overrideConfig: { plugins: ['deprecation'], rules: { 'deprecation/deprecation': 'error', }, parserOptions: { - project: [paths.resolveTargetRoot('tsconfig.json')], + project: [targetPaths.resolveTargetRoot('tsconfig.json')], }, }, extensions: ['jsx', 'ts', 'tsx', 'mjs', 'cjs'], @@ -55,7 +53,7 @@ export async function command(opts: OptionValues) { continue; } - const path = relativePath(paths.targetRoot, result.filePath); + const path = relativePath(targetPaths.targetRoot, 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 cc3e1bce69..ccf3a9c743 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -18,13 +18,11 @@ 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 { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export default async () => { - const { packages } = await getPackages(paths.targetDir); + const { packages } = await getPackages(targetPaths.targetDir); 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 202704e030..62e0376830 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -64,10 +64,14 @@ jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - findPaths: () => ({ - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); + targetPaths: { + resolveTargetRoot: (filename: string) => mockDir.resolve(filename), + get targetDir() { + return mockDir.path; }, + }, + findPaths: () => ({ + resolveTargetRoot: (filename: string) => mockDir.resolve(filename), get targetDir() { return mockDir.path; }, diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index 8a12683abc..c25be51ef8 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -13,10 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BACKSTAGE_JSON, bootstrapEnvProxyAgents, findPaths } from '@backstage/cli-common'; +import { BACKSTAGE_JSON, bootstrapEnvProxyAgents, targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); bootstrapEnvProxyAgents(); @@ -71,7 +69,7 @@ function extendsDefaultPattern(pattern: string): boolean { } export default async (opts: OptionValues) => { - const lockfilePath = paths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveTargetRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); const hasYarnPlugin = await getHasYarnPlugin(); @@ -143,7 +141,7 @@ 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.targetDir, pattern); // Next check with the package registry to see which dependency ranges we need to bump const versionBumps = new Map(); @@ -420,7 +418,7 @@ export function createVersionFinder(options: { } function getBackstageJsonPath() { - return paths.resolveTargetRoot(BACKSTAGE_JSON); + return targetPaths.resolveTargetRoot(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 936d10e24c..0a176c0182 100644 --- a/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts @@ -37,10 +37,14 @@ jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - findPaths: () => ({ - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); + targetPaths: { + resolveTargetRoot: (filename: string) => mockDir.resolve(filename), + get targetDir() { + return mockDir.path; }, + }, + findPaths: () => ({ + resolveTargetRoot: (filename: string) => mockDir.resolve(filename), get targetDir() { return mockDir.path; }, diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index 685363bdd3..e3b8f0d1b4 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import path from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; @@ -85,7 +83,7 @@ export async function addCodeownersEntry( let filePath = codeownersFilePath; if (!filePath) { - filePath = await getCodeownersFilePath(paths.targetRoot); + filePath = await getCodeownersFilePath(targetPaths.targetRoot); 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 084c9d2d33..1e83828701 100644 --- a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts +++ b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts @@ -25,10 +25,8 @@ import upperCase from 'lodash/upperCase'; import upperFirst from 'lodash/upperFirst'; import lowerFirst from 'lodash/lowerFirst'; import { Lockfile } from '../../../../lib/versioning'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { createPackageVersionProvider } from '../../../../lib/version'; import { getHasYarnPlugin } from '../../../../lib/yarnPlugin'; @@ -52,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.resolveTargetRoot('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 7281689ff5..71208b685e 100644 --- a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts +++ b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import upperFirst from 'lodash/upperFirst'; import camelCase from 'lodash/camelCase'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { Task } from '../tasks'; import { PortableTemplateInput } from '../types'; @@ -55,7 +53,7 @@ export async function installNewPackage(input: PortableTemplateInput) { } async function addDependency(input: PortableTemplateInput, path: string) { - const pkgJsonPath = paths.resolveTargetRoot(path); + const pkgJsonPath = targetPaths.resolveTargetRoot(path); const pkgJson = await fs.readJson(pkgJsonPath).catch(error => { if (error.code === 'ENOENT') { @@ -87,7 +85,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { ); } - const appDefinitionPath = paths.resolveTargetRoot('packages/app/src/App.tsx'); + const appDefinitionPath = targetPaths.resolveTargetRoot('packages/app/src/App.tsx'); if (!(await fs.pathExists(appDefinitionPath))) { return; } @@ -123,7 +121,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { } async function tryAddBackend(input: PortableTemplateInput) { - const backendIndexPath = paths.resolveTargetRoot( + const backendIndexPath = targetPaths.resolveTargetRoot( '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 2a4cb8a8c5..d17e1081e0 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts @@ -17,10 +17,8 @@ import { relative as relativePath } from 'node:path'; import { writeTemplateContents } from './writeTemplateContents'; import { createMockDirectory } from '@backstage/backend-test-utils'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); const baseConfig = { version: '0.1.0', @@ -35,7 +33,7 @@ describe('writeTemplateContents', () => { mockDir.clear(); jest.resetAllMocks(); jest - .spyOn(paths, 'resolveTargetRoot') + .spyOn(targetPaths, 'resolveTargetRoot') .mockImplementation((...args) => mockDir.resolve(...args)); }); diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index 99e6a1931f..8359468ba0 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -22,16 +22,14 @@ 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, findPaths } from '@backstage/cli-common'; +import { isChildPath, targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); export async function writeTemplateContents( template: PortableTemplate, input: PortableTemplateInput, ): Promise<{ targetDir: string }> { - const targetDir = paths.resolveTargetRoot(input.packagePath); + const targetDir = targetPaths.resolveTargetRoot(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 7a6046f927..168e277fb6 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -16,10 +16,8 @@ import inquirer, { DistinctQuestion } from 'inquirer'; import { getCodeownersFilePath, parseOwnerIds } from '../codeowners'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { PortableTemplateConfig, PortableTemplateInput, @@ -41,7 +39,7 @@ export async function collectPortableTemplateInput( ): Promise { const { config, template, prefilledParams } = options; - const codeOwnersFilePath = await getCodeownersFilePath(paths.targetRoot); + const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.targetRoot); 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 8b77296249..6d230c14cf 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts @@ -20,10 +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 { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { PortableTemplateFile, PortableTemplatePointer, @@ -49,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.resolveTargetRoot(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 61e04a20a5..c996bc9194 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts @@ -16,10 +16,8 @@ import fs from 'fs-extra'; import { resolve as resolvePath, dirname, isAbsolute } from 'node:path'; -import { findPaths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); import { defaultTemplates } from '../defaultTemplates'; import { PortableTemplateConfig, @@ -93,7 +91,7 @@ export async function loadPortableTemplateConfig( ): Promise { const { overrides = {} } = options; const pkgPath = - options.packagePath ?? paths.resolveTargetRoot('package.json'); + options.packagePath ?? targetPaths.resolveTargetRoot('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 e425af4962..3dd3399bd2 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -16,10 +16,9 @@ import { Command, OptionValues } from 'commander'; -import { runCheck, findPaths } from '@backstage/cli-common'; +import { runCheck, findOwnPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); +const ownPaths = findOwnPaths(__dirname); function includesAnyOf(hayStack: string[], ...needles: string[]) { for (const needle of needles) { @@ -41,7 +40,7 @@ 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')); + args.push('--config', ownPaths.resolveOwn('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 717f15e788..ae0882719f 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -24,10 +24,9 @@ import { relative as relativePath } from 'node:path'; import { Command, OptionValues } from 'commander'; import { Lockfile, PackageGraph } from '@backstage/cli-node'; -import { runCheck, runOutput, findPaths } from '@backstage/cli-common'; +import { runCheck, runOutput, targetPaths, findOwnPaths } from '@backstage/cli-common'; -/* eslint-disable-next-line no-restricted-syntax */ -const paths = findPaths(__dirname); +const ownPaths = findOwnPaths(__dirname); import { isChildPath } from '@backstage/cli-common'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; @@ -66,7 +65,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.targetRoot, pkg.dir), })); const output = await runOutput([ 'git', @@ -165,7 +164,7 @@ 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')); + args.push('--config', ownPaths.resolveOwn('config/jest.js')); } if (!hasFlags('--passWithNoTests')) { @@ -344,7 +343,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.resolveTargetRoot('yarn.lock'), ); const getPackageTreeHash = await readPackageTreeHashes(graph); From 70fc178697cc59e7622b645c41c5e4cb45b2c6a5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 21 Feb 2026 15:16:58 +0100 Subject: [PATCH 35/62] Replace findPaths with targetPaths and findOwnPaths Split the path resolution API in @backstage/cli-common into targetPaths (cwd-based singleton) and findOwnPaths (package-relative). Migrate all consumers across the repo away from the deprecated findPaths. Rename TargetPaths/OwnPaths properties to resolve/resolveRoot, removing the redundant type prefix from property names. Make findOwnPaths calls lazy in modules - called inside functions rather than at module scope. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/cli-common-cached-paths.md | 4 +- .changeset/migrate-to-target-paths.md | 11 +++ .../src/manager/plugin-manager.test.ts | 31 ++++++- .../src/manager/plugin-manager.ts | 4 +- .../src/schemas/schemas.ts | 4 +- packages/backend/src/index.ts | 2 +- packages/cli-common/src/paths.ts | 93 +++++++------------ packages/cli-node/src/paths.ts | 23 ++++- packages/cli/src/lib/cache/SuccessCache.ts | 2 +- packages/cli/src/lib/typeDistProject.ts | 2 +- packages/cli/src/lib/version.ts | 6 +- packages/cli/src/lib/yarnPlugin.test.ts | 17 ++-- packages/cli/src/lib/yarnPlugin.ts | 2 +- .../build/commands/package/build/command.ts | 10 +- .../build/commands/package/start/command.ts | 2 +- .../commands/package/start/startBackend.ts | 2 +- .../commands/package/start/startFrontend.ts | 4 +- .../src/modules/build/commands/repo/build.ts | 2 +- .../modules/build/commands/repo/start.test.ts | 2 +- .../src/modules/build/commands/repo/start.ts | 4 +- .../src/modules/build/lib/builder/config.ts | 6 +- .../src/modules/build/lib/builder/packager.ts | 10 +- .../src/modules/build/lib/bundler/config.ts | 2 +- .../build/lib/bundler/hasReactDomClient.ts | 2 +- .../build/lib/bundler/linkWorkspaces.ts | 2 +- .../build/lib/bundler/packageDetection.ts | 2 +- .../src/modules/build/lib/bundler/paths.ts | 14 ++- .../src/modules/build/lib/bundler/server.ts | 4 +- .../build/lib/packager/createDistWorkspace.ts | 10 +- .../cli/src/modules/build/lib/role.test.ts | 5 +- packages/cli/src/modules/build/lib/role.ts | 2 +- .../modules/build/lib/runner/runBackend.ts | 2 +- packages/cli/src/modules/config/lib/config.ts | 6 +- .../commands/create-github-app/index.ts | 2 +- .../cli/src/modules/info/commands/info.ts | 11 +-- .../src/modules/lint/commands/package/lint.ts | 6 +- .../src/modules/lint/commands/repo/lint.ts | 10 +- .../maintenance/commands/package/clean.ts | 6 +- .../maintenance/commands/package/pack.ts | 8 +- .../maintenance/commands/repo/clean.ts | 6 +- .../modules/maintenance/commands/repo/fix.ts | 12 +-- .../commands/repo/list-deprecations.ts | 6 +- .../modules/migrate/commands/packageRole.ts | 2 +- .../migrate/commands/versions/bump.test.ts | 8 +- .../modules/migrate/commands/versions/bump.ts | 6 +- .../migrate/commands/versions/migrate.test.ts | 8 +- .../modules/new/lib/codeowners/codeowners.ts | 2 +- .../new/lib/execution/PortableTemplater.ts | 2 +- .../new/lib/execution/installNewPackage.ts | 6 +- .../execution/writeTemplateContents.test.ts | 4 +- .../lib/execution/writeTemplateContents.ts | 2 +- .../collectPortableTemplateInput.ts | 2 +- .../lib/preparation/loadPortableTemplate.ts | 2 +- .../preparation/loadPortableTemplateConfig.ts | 2 +- .../src/modules/test/commands/package/test.ts | 4 +- .../src/modules/test/commands/repo/test.ts | 17 ++-- packages/codemods/src/action.ts | 9 +- .../src/sources/ConfigSources.ts | 4 +- packages/create-app/src/createApp.test.ts | 49 ++++++---- packages/create-app/src/createApp.ts | 16 ++-- packages/e2e-test/src/commands/runCommand.ts | 21 +++-- packages/repo-tools/src/lib/paths.ts | 27 ++++-- .../techdocs-cli/src/commands/serve/serve.ts | 5 +- packages/yarn-plugin/src/index.test.ts | 4 +- .../src/util/getWorkspaceRoot.test.ts | 14 +-- .../yarn-plugin/src/util/getWorkspaceRoot.ts | 8 +- 66 files changed, 311 insertions(+), 274 deletions(-) create mode 100644 .changeset/migrate-to-target-paths.md diff --git a/.changeset/cli-common-cached-paths.md b/.changeset/cli-common-cached-paths.md index 27a683e35a..a82a5434b0 100644 --- a/.changeset/cli-common-cached-paths.md +++ b/.changeset/cli-common-cached-paths.md @@ -1,5 +1,5 @@ --- -'@backstage/cli-common': patch +'@backstage/cli-common': minor --- -Added hierarchical caching to `findOwnDir`, avoiding redundant filesystem walks when `findPaths` is called from multiple locations within the same package. +Added `targetPaths` and `findOwnPaths` as replacements for `findPaths`, with a cleaner separation between target project paths and package-relative paths. diff --git a/.changeset/migrate-to-target-paths.md b/.changeset/migrate-to-target-paths.md new file mode 100644 index 0000000000..b3f983bffc --- /dev/null +++ b/.changeset/migrate-to-target-paths.md @@ -0,0 +1,11 @@ +--- +'@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 +'@backstage/techdocs-cli': patch +--- + +Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. 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..011aae0457 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,8 +38,33 @@ 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'; + +jest.mock('@backstage/cli-common', () => { + const path = require('path'); + const actual = jest.requireActual( + '@backstage/cli-common', + ); + const mockRoot = path.resolve(__dirname, '..', '..', '..', '..'); + return { + ...actual, + targetPaths: { + resolve: (...paths: string[]) => path.join(mockRoot, ...paths), + resolveRoot: (...paths: string[]) => path.join(mockRoot, ...paths), + }, + findPaths: (searchDir: string) => ({ + targetRoot: mockRoot, + targetDir: mockRoot, + ownDir: path.dirname(searchDir), + ownRoot: mockRoot, + resolveOwn: (...p: string[]) => path.join(path.dirname(searchDir), ...p), + resolveOwnRoot: (...p: string[]) => path.join(mockRoot, ...p), + resolveTarget: (...p: string[]) => path.join(mockRoot, ...p), + resolveTargetRoot: (...p: string[]) => path.join(mockRoot, ...p), + }), + }; +}); import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; @@ -956,7 +981,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 +1069,7 @@ describe('backend-dynamic-feature-service', () => { otherMockDir.resolve('a-dynamic-plugin'), ); expect(mockedModuleLoader.bootstrap).toHaveBeenCalledWith( - findPaths(__dirname).targetRoot, + targetPaths.resolveRoot(), [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..5fe4f7241c 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.resolveRoot(); 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..3a1bc666b0 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.resolveRoot(), preferAlpha: true, }); diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 9c42c6b740..14eb36a3a6 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -32,7 +32,7 @@ const searchLoader = createBackendFeatureLoader({ *loader({ config }) { yield import('@backstage/plugin-search-backend'); yield import('@backstage/plugin-search-backend-module-catalog'); - yield import('@backstage-community/plugin-search-backend-module-explore'); + yield import('@backstage/plugin-search-backend-module-explore'); yield import('@backstage/plugin-search-backend-module-techdocs'); if (config.has('search.elasticsearch')) { yield import('@backstage/plugin-search-backend-module-elasticsearch'); diff --git a/packages/cli-common/src/paths.ts b/packages/cli-common/src/paths.ts index c0e80b24f6..15cdc7b89c 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -26,45 +26,31 @@ import { dirname, resolve as resolvePath } from 'node:path'; export type ResolveFunc = (...paths: string[]) => string; /** - * Paths relative to the target project that the CLI is operating on, based on - * `process.cwd()`. This can be imported directly — no `__dirname` needed. - * - * Lazily initialized on first access and re-resolved if `process.cwd()` changes. + * 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 location of the app that the cli is being executed in - targetDir: string; + /** Resolve a path relative to the target package directory. */ + resolve: ResolveFunc; - // The monorepo root package of the app that the cli is being executed in. - targetRoot: string; - - // Resolve a path relative to the app - resolveTarget: ResolveFunc; - - // Resolve a path relative to the app repo root - resolveTargetRoot: ResolveFunc; + /** Resolve a path relative to the target repo root. */ + resolveRoot: ResolveFunc; }; /** - * Paths relative to the package that the calling code lives in. Requires - * `__dirname` to locate the package root. + * Resolved paths relative to a specific package in the repository. * * @public */ export type OwnPaths = { - // Root dir of the package itself, containing package.json - ownDir: string; + /** Resolve a path relative to the package root. */ + resolve: ResolveFunc; - // Monorepo root dir of the package. Only accessible when running inside Backstage repo. - ownRoot: string; - - // Resolve a path relative to own package - 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 monorepo root containing the package. */ + resolveRoot: ResolveFunc; }; /** @@ -211,41 +197,34 @@ function getTargetRoot(): string { * Lazily resolved paths relative to the target project. Import this directly * for cwd-based path resolution without needing `__dirname`. * - * Re-resolves automatically if `process.cwd()` changes. - * * @public * @example * - * import { targetPaths } from '@backstage/cli-common'; + * import { targetPaths } from '\@backstage/cli-common'; * - * const root = targetPaths.targetRoot; - * const lockfile = targetPaths.resolveTargetRoot('yarn.lock'); + * const lockfile = targetPaths.resolveRoot('yarn.lock'); */ export const targetPaths: TargetPaths = { - get targetDir() { - return getTargetDir(); - }, - get targetRoot() { - return getTargetRoot(); - }, - resolveTarget: (...paths) => resolvePath(getTargetDir(), ...paths), - resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), + resolve: (...paths) => resolvePath(getTargetDir(), ...paths), + resolveRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), }; const ownPathsCache = new Map(); /** - * Find paths relative to the package that the calling code lives in. Cheap to - * call repeatedly — results are cached per package root, and the package root - * lookup uses a hierarchical cache so sibling directories share work. + * 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 * @example * - * import { findOwnPaths } from '@backstage/cli-common'; + * import { findOwnPaths } from '\@backstage/cli-common'; * - * const ownPaths = findOwnPaths(__dirname); - * const config = ownPaths.resolveOwn('config/jest.js'); + * const own = findOwnPaths(__dirname); + * const config = own.resolve('config/jest.js'); */ export function findOwnPaths(searchDir: string): OwnPaths { const ownDir = findOwnDir(searchDir); @@ -263,12 +242,8 @@ export function findOwnPaths(searchDir: string): OwnPaths { }; const paths: OwnPaths = { - ownDir, - get ownRoot() { - return getOwnRoot(); - }, - resolveOwn: (...p) => resolvePath(ownDir, ...p), - resolveOwnRoot: (...p) => resolvePath(getOwnRoot(), ...p), + resolve: (...p) => resolvePath(ownDir, ...p), + resolveRoot: (...p) => resolvePath(getOwnRoot(), ...p), }; ownPathsCache.set(ownDir, paths); @@ -290,21 +265,21 @@ export function findPaths(searchDir: string): Paths { const own = findOwnPaths(searchDir); return { get ownDir() { - return own.ownDir; + return own.resolve(); }, get ownRoot() { - return own.ownRoot; + return own.resolveRoot(); }, get targetDir() { - return targetPaths.targetDir; + return targetPaths.resolve(); }, get targetRoot() { - return targetPaths.targetRoot; + return targetPaths.resolveRoot(); }, - resolveOwn: own.resolveOwn, - resolveOwnRoot: own.resolveOwnRoot, - resolveTarget: targetPaths.resolveTarget, - resolveTargetRoot: targetPaths.resolveTargetRoot, + resolveOwn: own.resolve, + resolveOwnRoot: own.resolveRoot, + resolveTarget: targetPaths.resolve, + resolveTargetRoot: targetPaths.resolveRoot, }; } diff --git a/packages/cli-node/src/paths.ts b/packages/cli-node/src/paths.ts index 2c658c27b3..57c98ea0a8 100644 --- a/packages/cli-node/src/paths.ts +++ b/packages/cli-node/src/paths.ts @@ -14,7 +14,26 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; +import { targetPaths, findOwnPaths } from '@backstage/cli-common'; + +const ownPaths = findOwnPaths(__dirname); /* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); +export const paths = { + get ownDir() { + return ownPaths.resolve(); + }, + get ownRoot() { + return ownPaths.resolveRoot(); + }, + get targetDir() { + return targetPaths.resolve(); + }, + get targetRoot() { + return targetPaths.resolveRoot(); + }, + resolveOwn: ownPaths.resolve, + resolveOwnRoot: ownPaths.resolveRoot, + resolveTarget: targetPaths.resolve, + resolveTargetRoot: targetPaths.resolveRoot, +}; diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index bf7436ed62..495baf660c 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -32,7 +32,7 @@ export class SuccessCache { * location. */ static trimPaths(input: string) { - return input.replaceAll(targetPaths.targetRoot, ''); + return input.replaceAll(targetPaths.resolveRoot(), ''); } constructor(name: string, basePath?: string) { diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index 161ea2be82..11a0019490 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -25,7 +25,7 @@ import { targetPaths } from '@backstage/cli-common'; export const createTypeDistProject = async () => { return new Project({ - tsConfigFilePath: targetPaths.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 326657a9b0..a28feba015 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -17,9 +17,9 @@ import fs from 'fs-extra'; import semver from 'semver'; import { findOwnPaths } from '@backstage/cli-common'; +import { Lockfile } from './versioning'; const ownPaths = findOwnPaths(__dirname); -import { Lockfile } from './versioning'; /* eslint-disable @backstage/no-relative-monorepo-imports */ /* @@ -84,12 +84,12 @@ export const packageVersions: Record = { }; export function findVersion() { - const pkgContent = fs.readFileSync(ownPaths.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(ownPaths.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 ac9345a4a4..a51fa4864a 100644 --- a/packages/cli/src/lib/yarnPlugin.test.ts +++ b/packages/cli/src/lib/yarnPlugin.test.ts @@ -15,22 +15,21 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; +import { targetPaths } from '@backstage/cli-common'; import { getHasYarnPlugin } from './yarnPlugin'; const mockDir = createMockDirectory(); -jest.mock('@backstage/cli-common', () => ({ - ...jest.requireActual('@backstage/cli-common'), - targetPaths: { - resolveTargetRoot(filename: string) { - return mockDir.resolve(filename); - }, - }, -})); - describe('getHasYarnPlugin', () => { beforeEach(() => { mockDir.clear(); + jest + .spyOn(targetPaths, 'resolveRoot') + .mockImplementation((...args: string[]) => mockDir.resolve(...args)); + }); + + afterEach(() => { + jest.restoreAllMocks(); }); it('should return false when .yarnrc.yml does not exist', async () => { diff --git a/packages/cli/src/lib/yarnPlugin.ts b/packages/cli/src/lib/yarnPlugin.ts index b8c56b98ec..fdef27e07f 100644 --- a/packages/cli/src/lib/yarnPlugin.ts +++ b/packages/cli/src/lib/yarnPlugin.ts @@ -36,7 +36,7 @@ const yarnRcSchema = z.object({ * @returns Promise - true if the plugin is installed, false otherwise */ export async function getHasYarnPlugin(): Promise { - const yarnRcPath = targetPaths.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 6a04524d17..408d7dab52 100644 --- a/packages/cli/src/modules/build/commands/package/build/command.ts +++ b/packages/cli/src/modules/build/commands/package/build/command.ts @@ -42,19 +42,19 @@ export async function command(opts: OptionValues): Promise { if (isValidUrl(arg)) { return arg; } - return targetPaths.resolveTarget(arg); + return targetPaths.resolve(arg); }); if (role === 'frontend') { return buildFrontend({ - targetDir: targetPaths.targetDir, + targetDir: targetPaths.resolve(), configPaths, writeStats: Boolean(opts.stats), webpack, }); } return buildBackend({ - targetDir: targetPaths.targetDir, + targetDir: targetPaths.resolve(), configPaths, skipBuildDependencies: Boolean(opts.skipBuildDependencies), minify: Boolean(opts.minify), @@ -77,7 +77,7 @@ export async function command(opts: OptionValues): Promise { if (isModuleFederationRemote) { console.log('Building package as a module federation remote'); return buildFrontend({ - targetDir: targetPaths.targetDir, + targetDir: targetPaths.resolve(), configPaths: [], writeStats: Boolean(opts.stats), isModuleFederationRemote, @@ -100,7 +100,7 @@ export async function command(opts: OptionValues): Promise { } const packageJson = (await fs.readJson( - targetPaths.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 fb9f10deac..9bc0bfc841 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -25,7 +25,7 @@ export async function command(opts: OptionValues): Promise { await startPackage({ role: await findRoleFromCommand(opts), entrypoint: opts.entrypoint, - targetDir: targetPaths.targetDir, + targetDir: targetPaths.resolve(), 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 7a593bb7d7..3ea1e9bbe9 100644 --- a/packages/cli/src/modules/build/commands/package/start/startBackend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startBackend.ts @@ -44,7 +44,7 @@ export async function startBackend(options: StartBackendOptions) { export async function startBackendPlugin(options: StartBackendOptions) { const hasDevIndexEntry = await fs.pathExists( - resolvePath(options.targetDir ?? targetPaths.targetDir, 'dev/index.ts'), + resolvePath(options.targetDir ?? targetPaths.resolve(), '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 60b4fab14d..413ce6b752 100644 --- a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts @@ -39,7 +39,7 @@ interface StartAppOptions { export async function startFrontend(options: StartAppOptions) { const packageJson = (await readJson( - resolvePath(options.targetDir ?? targetPaths.targetDir, 'package.json'), + resolvePath(options.targetDir ?? targetPaths.resolve(), 'package.json'), )) as BackstagePackageJson; if (!hasReactDomClient()) { @@ -59,7 +59,7 @@ export async function startFrontend(options: StartAppOptions) { moduleFederationRemote: options.isModuleFederationRemote ? await getModuleFederationRemoteOptions( packageJson, - resolvePath(targetPaths.targetDir), + resolvePath(targetPaths.resolve()), ) : undefined, }); diff --git a/packages/cli/src/modules/build/commands/repo/build.ts b/packages/cli/src/modules/build/commands/repo/build.ts index 22530875f5..8b1391ecf9 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -90,7 +90,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { targetDir: pkg.dir, packageJson: pkg.packageJson, outputs, - logPrefix: `${chalk.cyan(relativePath(targetPaths.targetRoot, pkg.dir))}: `, + logPrefix: `${chalk.cyan(relativePath(targetPaths.resolveRoot(), pkg.dir))}: `, workspacePackages: packages, minify: opts.minify ?? buildOptions.minify, }; 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 cc9e5cd8ec..4cb3449e12 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -99,7 +99,7 @@ describe('findTargetPackages', () => { beforeEach(() => { jest.clearAllMocks(); jest - .spyOn(targetPaths, 'resolveTargetRoot') + .spyOn(targetPaths, 'resolveRoot') .mockImplementation((...parts: string[]) => { return posix.resolve('/root', ...parts); }); diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index cd45c7941e..f7faa46eb1 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -96,7 +96,7 @@ export async function findTargetPackages( pkg => nameOrPath === pkg.packageJson.name, ); if (!matchingPackage) { - const absPath = targetPaths.resolveTargetRoot(nameOrPath); + const absPath = targetPaths.resolveRoot(nameOrPath); matchingPackage = packages.find( pkg => relativePath(pkg.dir, absPath) === '', ); @@ -118,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 = targetPaths.resolveTargetRoot( + const expectedPath = targetPaths.resolveRoot( role === 'frontend' ? 'packages/app' : 'packages/backend', ); const matchByPath = matchingPackages.find( diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index ba8028f2d6..08b8221a77 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -117,7 +117,7 @@ export async function makeRollupConfigs( options: BuildOptions, ): Promise { const configs = new Array(); - const targetDir = options.targetDir ?? targetPaths.targetDir; + const targetDir = options.targetDir ?? targetPaths.resolve(); let targetPkg = options.packageJson; if (!targetPkg) { @@ -285,9 +285,9 @@ export async function makeRollupConfigs( const input = Object.fromEntries( scriptEntryPoints.map(e => [ e.name, - targetPaths.resolveTargetRoot( + targetPaths.resolveRoot( 'dist-types', - relativePath(targetPaths.targetRoot, targetDir), + relativePath(targetPaths.resolveRoot(), 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 e1a10b3ac8..527fbbba0e 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -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(targetPaths.targetDir, error.id); + const path = relativePath(targetPaths.resolve(), 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 = `${targetPaths.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 += `${targetPaths.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( - targetPaths.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 ?? targetPaths.targetDir; + const targetDir = options.targetDir ?? targetPaths.resolve(); await fs.remove(resolvePath(targetDir, 'dist')); const buildTasks = rollupConfigs.map(rollupBuild); diff --git a/packages/cli/src/modules/build/lib/bundler/config.ts b/packages/cli/src/modules/build/lib/bundler/config.ts index c0537bb36c..1fe81cbec8 100644 --- a/packages/cli/src/modules/build/lib/bundler/config.ts +++ b/packages/cli/src/modules/build/lib/bundler/config.ts @@ -97,7 +97,7 @@ async function readBuildInfo() { } const { version: packageVersion } = await fs.readJson( - targetPaths.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 ab48599033..6acd96f8c1 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -20,7 +20,7 @@ import { targetPaths } from '@backstage/cli-common'; export function hasReactDomClient() { try { require.resolve('react-dom/client', { - paths: [targetPaths.targetDir], + paths: [targetPaths.resolve()], }); 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 6976df99a5..935e14e85a 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -53,7 +53,7 @@ export async function createWorkspaceLinkingPlugins( /^react(?:-router)?(?:-dom)?$/, resource => { if (!relativePath(linkedRoot.dir, resource.context).startsWith('..')) { - resource.context = targetPaths.targetDir; + resource.context = targetPaths.resolve(); } }, ), diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index e0a3069733..3f361819f3 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -147,7 +147,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( - targetPaths.targetRoot, + targetPaths.resolveRoot(), '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 166fc20d5b..d0d56e6396 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -18,19 +18,17 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { targetPaths, findOwnPaths } from '@backstage/cli-common'; -const ownPaths = findOwnPaths(__dirname); - export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' entry: string; - // Target directory, defaulting to targetPaths.targetDir + // Target directory, defaulting to targetPaths.resolve() targetDir?: string; // Relative dist directory, defaulting to 'dist' dist?: string; }; export function resolveBundlingPaths(options: BundlingPathsOptions) { - const { entry, targetDir = targetPaths.targetDir } = options; + const { entry, targetDir = targetPaths.resolve() } = options; const resolveTargetModule = (pathString: string) => { for (const ext of ['mjs', 'js', 'ts', 'tsx', 'jsx']) { @@ -51,7 +49,7 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { } else { targetHtml = resolvePath(targetDir, `${entry}.html`); if (!fs.pathExistsSync(targetHtml)) { - targetHtml = ownPaths.resolveOwn('templates/serve_index.html'); + targetHtml = findOwnPaths(__dirname).resolve('templates/serve_index.html'); } } @@ -69,10 +67,10 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetSrc: resolvePath(targetDir, 'src'), targetDev: resolvePath(targetDir, 'dev'), targetEntry: resolveTargetModule(entry), - targetTsConfig: targetPaths.resolveTargetRoot('tsconfig.json'), + targetTsConfig: targetPaths.resolveRoot('tsconfig.json'), targetPackageJson: resolvePath(targetDir, 'package.json'), - rootNodeModules: targetPaths.resolveTargetRoot('node_modules'), - root: targetPaths.targetRoot, + rootNodeModules: targetPaths.resolveRoot('node_modules'), + root: targetPaths.resolveRoot(), }; } diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index f729a0a084..27e0cbd034 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -54,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 ?? targetPaths.targetDir, 'package.json'), + resolvePath(options.targetDir ?? targetPaths.resolve(), 'package.json'), ); let devServer: RspackDevServer | undefined = undefined; @@ -272,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: [targetPaths.targetRoot], + paths: [targetPaths.resolveRoot()], }); const reactPkg = require(reactPkgPath); if (reactPkg.version.startsWith('16.')) { diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 0312108c88..6d55fdac0f 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -211,7 +211,7 @@ export async function createDistWorkspace( targetDir: pkg.dir, packageJson: pkg.packageJson, outputs: outputs, - logPrefix: `${chalk.cyan(relativePath(targetPaths.targetRoot, pkg.dir))}: `, + logPrefix: `${chalk.cyan(relativePath(targetPaths.resolveRoot(), pkg.dir))}: `, minify: options.minify, workspacePackages: packages, }); @@ -246,13 +246,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(targetPaths.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(targetPaths.targetRoot, target.dir); + const dir = relativePath(targetPaths.resolveRoot(), target.dir); return joinPath(dir, 'package.json'); }) .sort(); @@ -301,7 +301,7 @@ async function moveToDistWorkspace( fastPackPackages.map(async target => { console.log(`Moving ${target.name} into dist workspace`); - const outputDir = relativePath(targetPaths.targetRoot, target.dir); + const outputDir = relativePath(targetPaths.resolveRoot(), target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await productionPack({ packageDir: target.dir, @@ -321,7 +321,7 @@ async function moveToDistWorkspace( cwd: target.dir, }).waitForExit(); - const outputDir = relativePath(targetPaths.targetRoot, target.dir); + const outputDir = relativePath(targetPaths.resolveRoot(), target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await fs.ensureDir(absoluteOutputPath); diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index 83372e010f..1e26f78f33 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -23,9 +23,8 @@ const mockDir = createMockDirectory(); jest.mock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), targetPaths: { - resolveTarget(filename: string) { - return mockDir.resolve(filename); - }, + resolve: (...args: string[]) => mockDir.resolve(...args), + resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, })); diff --git a/packages/cli/src/modules/build/lib/role.ts b/packages/cli/src/modules/build/lib/role.ts index 95ef580048..2f3960433b 100644 --- a/packages/cli/src/modules/build/lib/role.ts +++ b/packages/cli/src/modules/build/lib/role.ts @@ -27,7 +27,7 @@ export async function findRoleFromCommand( return PackageRoles.getRoleInfo(opts.role)?.role; } - const pkg = await fs.readJson(targetPaths.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 2291395246..22fd50b3f4 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -136,7 +136,7 @@ export async function runBackend(options: RunBackendOptions) { ...process.env, BACKSTAGE_CLI_LINKED_WORKSPACE: options.linkedWorkspace, BACKSTAGE_CLI_CHANNEL: '1', - ESBK_TSCONFIG_PATH: targetPaths.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 da212e9269..b819d1da7b 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -35,7 +35,7 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const targetDir = options.targetDir ?? targetPaths.targetDir; + const targetDir = options.targetDir ?? targetPaths.resolve(); // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(targetDir); @@ -64,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: [targetPaths.resolveTargetRoot('package.json')], + packagePaths: [targetPaths.resolveRoot('package.json')], noUndeclaredProperties: options.strict, }); @@ -74,7 +74,7 @@ export async function loadCliConfig(options: Options) { ? async name => process.env[name] || 'x' : undefined, watch: Boolean(options.watch), - rootDir: targetPaths.targetRoot, + rootDir: targetPaths.resolveRoot(), 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 61f7f43cab..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 @@ -63,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(targetPaths.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 f74529f7ae..b0ce28fb7d 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -17,9 +17,6 @@ import { version as cliVersion } from '../../../../package.json'; import os from 'node:os'; import { runOutput, targetPaths, findOwnPaths } from '@backstage/cli-common'; - -const ownPaths = findOwnPaths(__dirname); - import { Lockfile } from '../../../lib/versioning'; import { BackstagePackageJson, PackageGraph } from '@backstage/cli-node'; import { minimatch } from 'minimatch'; @@ -58,9 +55,9 @@ 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(ownPaths.resolveOwn('./src')); + const isLocal = fs.existsSync(findOwnPaths(__dirname).resolve('./src')); - const backstageFile = targetPaths.resolveTargetRoot('backstage.json'); + const backstageFile = targetPaths.resolveRoot('backstage.json'); let backstageVersion = 'N/A'; if (fs.existsSync(backstageFile)) { try { @@ -85,9 +82,9 @@ export default async (options: InfoOptions) => { backstage: backstageVersion, }; - const lockfilePath = targetPaths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); - const targetPath = targetPaths.targetRoot; + const targetPath = targetPaths.resolveRoot(); // 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 e5d706373a..f75937f6d1 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -22,7 +22,7 @@ import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { const eslint = new ESLint({ - cwd: targetPaths.targetDir, + cwd: targetPaths.resolve(), fix: opts.fix, extensions: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'], }); @@ -48,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(targetPaths.targetRoot); + process.chdir(targetPaths.resolveRoot()); } const resultText = await formatter.format(results); if (resultText) { if (opts.outputFile) { - await fs.writeFile(targetPaths.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 67ba77fcca..3bdb8aae97 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -45,7 +45,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { const cacheContext = opts.successCache ? { entries: await cache.read(), - lockfile: await Lockfile.load(targetPaths.resolveTargetRoot('yarn.lock')), + lockfile: await Lockfile.load(targetPaths.resolveRoot('yarn.lock')), } : undefined; @@ -63,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(targetPaths.targetRoot); + process.chdir(targetPaths.resolveRoot()); } // Make sure lint output is colored unless the user explicitly disabled it @@ -78,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(targetPaths.targetRoot, pkg.dir), + relativeDir: relativePath(targetPaths.resolveRoot(), pkg.dir), lintOptions, parentHash: undefined, }; @@ -114,7 +114,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { shouldCache: Boolean(cacheContext), maxWarnings: opts.maxWarnings ?? -1, successCache: cacheContext?.entries, - rootDir: targetPaths.targetRoot, + rootDir: targetPaths.resolveRoot(), }, workerFactory: async ({ fix, @@ -264,7 +264,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { } if (opts.outputFile && errorOutput) { - await fs.writeFile(targetPaths.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 bebf5c6ec1..74c6761a50 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -19,7 +19,7 @@ import { targetPaths } from '@backstage/cli-common'; export default async function clean() { - await fs.remove(targetPaths.resolveTarget('dist')); - await fs.remove(targetPaths.resolveTarget('dist-types')); - await fs.remove(targetPaths.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 bd1e93cf5d..fd4c9dc162 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -26,16 +26,16 @@ import { createTypeDistProject } from '../../../../lib/typeDistProject'; export const pre = async () => { publishPreflightCheck({ - dir: targetPaths.targetDir, - packageJson: await fs.readJson(targetPaths.resolveTarget('package.json')), + dir: targetPaths.resolve(), + packageJson: await fs.readJson(targetPaths.resolve('package.json')), }); await productionPack({ - packageDir: targetPaths.targetDir, + packageDir: targetPaths.resolve(), featureDetectionProject: await createTypeDistProject(), }); }; export const post = async () => { - await revertProductionPack(targetPaths.targetDir); + await revertProductionPack(targetPaths.resolve()); }; diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index 490f6a850e..00f45ad967 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -24,9 +24,9 @@ import { run, targetPaths } from '@backstage/cli-common'; export async function command(): Promise { const packages = await PackageGraph.listTargetPackages(); - await fs.remove(targetPaths.resolveTargetRoot('dist')); - await fs.remove(targetPaths.resolveTargetRoot('dist-types')); - await fs.remove(targetPaths.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 63ade707ef..973436da97 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -50,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(targetPaths.resolveTargetRoot('package.json')); + const rootPkg = require(targetPaths.resolveRoot('package.json')); const fixCmd = rootPkg.scripts?.fix === 'backstage-cli repo fix' ? 'fix' @@ -217,7 +217,7 @@ export function fixSideEffects(pkg: FixablePackage) { } export function createRepositoryFieldFixer() { - const rootPkg = require(targetPaths.resolveTargetRoot('package.json')); + const rootPkg = require(targetPaths.resolveRoot('package.json')); const rootRepoField = rootPkg.repository; if (!rootRepoField) { return () => {}; @@ -230,7 +230,7 @@ export function createRepositoryFieldFixer() { return (pkg: FixablePackage) => { const expectedPath = posix.join( rootDir, - relativePath(targetPaths.targetRoot, pkg.dir), + relativePath(targetPaths.resolveRoot(), pkg.dir), ); const repoField = pkg.packageJson.repository; @@ -319,7 +319,7 @@ export function fixPluginId(pkg: FixablePackage) { role === 'backend-plugin-module') ) { const path = relativePath( - targetPaths.targetRoot, + targetPaths.resolveRoot(), 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}"`; @@ -415,7 +415,7 @@ export function fixPluginPackages( return; } const path = relativePath( - targetPaths.targetRoot, + targetPaths.resolveRoot(), resolvePath(pkg.dir, 'package.json'), ); const suggestedRole = @@ -464,7 +464,7 @@ export function fixPeerModules(pkg: FixablePackage) { } const packagePath = relativePath( - targetPaths.targetRoot, + targetPaths.resolveRoot(), 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 1444d1062e..5f80330247 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -26,14 +26,14 @@ export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); const eslint = new ESLint({ - cwd: targetPaths.targetDir, + cwd: targetPaths.resolve(), overrideConfig: { plugins: ['deprecation'], rules: { 'deprecation/deprecation': 'error', }, parserOptions: { - project: [targetPaths.resolveTargetRoot('tsconfig.json')], + project: [targetPaths.resolveRoot('tsconfig.json')], }, }, extensions: ['jsx', 'ts', 'tsx', 'mjs', 'cjs'], @@ -53,7 +53,7 @@ export async function command(opts: OptionValues) { continue; } - const path = relativePath(targetPaths.targetRoot, result.filePath); + const path = relativePath(targetPaths.resolveRoot(), 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 ccf3a9c743..878d69a312 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -22,7 +22,7 @@ import { targetPaths } from '@backstage/cli-common'; export default async () => { - const { packages } = await getPackages(targetPaths.targetDir); + const { packages } = await getPackages(targetPaths.resolve()); 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 62e0376830..8f7ac2577b 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -65,13 +65,11 @@ jest.mock('@backstage/cli-common', () => { return { ...actual, targetPaths: { - resolveTargetRoot: (filename: string) => mockDir.resolve(filename), - get targetDir() { - return mockDir.path; - }, + resolve: (...args: string[]) => mockDir.resolve(...args), + resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, findPaths: () => ({ - resolveTargetRoot: (filename: string) => mockDir.resolve(filename), + resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), get targetDir() { return mockDir.path; }, diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index c25be51ef8..c508babb05 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -69,7 +69,7 @@ function extendsDefaultPattern(pattern: string): boolean { } export default async (opts: OptionValues) => { - const lockfilePath = targetPaths.resolveTargetRoot('yarn.lock'); + const lockfilePath = targetPaths.resolveRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); const hasYarnPlugin = await getHasYarnPlugin(); @@ -141,7 +141,7 @@ export default async (opts: OptionValues) => { } // First we discover all Backstage dependencies within our own repo - const dependencyMap = await mapDependencies(targetPaths.targetDir, pattern); + const dependencyMap = await mapDependencies(targetPaths.resolve(), pattern); // Next check with the package registry to see which dependency ranges we need to bump const versionBumps = new Map(); @@ -418,7 +418,7 @@ export function createVersionFinder(options: { } function getBackstageJsonPath() { - return targetPaths.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 0a176c0182..75361b0a07 100644 --- a/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts @@ -38,13 +38,11 @@ jest.mock('@backstage/cli-common', () => { return { ...actual, targetPaths: { - resolveTargetRoot: (filename: string) => mockDir.resolve(filename), - get targetDir() { - return mockDir.path; - }, + resolve: (...args: string[]) => mockDir.resolve(...args), + resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, findPaths: () => ({ - resolveTargetRoot: (filename: string) => mockDir.resolve(filename), + resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), get targetDir() { return mockDir.path; }, diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index e3b8f0d1b4..7842acaaa9 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -83,7 +83,7 @@ export async function addCodeownersEntry( let filePath = codeownersFilePath; if (!filePath) { - filePath = await getCodeownersFilePath(targetPaths.targetRoot); + filePath = await getCodeownersFilePath(targetPaths.resolveRoot()); 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 1e83828701..511e656c91 100644 --- a/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts +++ b/packages/cli/src/modules/new/lib/execution/PortableTemplater.ts @@ -50,7 +50,7 @@ export class PortableTemplater { static async create(options: CreatePortableTemplaterOptions = {}) { let lockfile: Lockfile | undefined; try { - lockfile = await Lockfile.load(targetPaths.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 71208b685e..4bbb3730df 100644 --- a/packages/cli/src/modules/new/lib/execution/installNewPackage.ts +++ b/packages/cli/src/modules/new/lib/execution/installNewPackage.ts @@ -53,7 +53,7 @@ export async function installNewPackage(input: PortableTemplateInput) { } async function addDependency(input: PortableTemplateInput, path: string) { - const pkgJsonPath = targetPaths.resolveTargetRoot(path); + const pkgJsonPath = targetPaths.resolveRoot(path); const pkgJson = await fs.readJson(pkgJsonPath).catch(error => { if (error.code === 'ENOENT') { @@ -85,7 +85,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { ); } - const appDefinitionPath = targetPaths.resolveTargetRoot('packages/app/src/App.tsx'); + const appDefinitionPath = targetPaths.resolveRoot('packages/app/src/App.tsx'); if (!(await fs.pathExists(appDefinitionPath))) { return; } @@ -121,7 +121,7 @@ async function tryAddFrontendLegacy(input: PortableTemplateInput) { } async function tryAddBackend(input: PortableTemplateInput) { - const backendIndexPath = targetPaths.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 d17e1081e0..e991d45b51 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts @@ -33,8 +33,8 @@ describe('writeTemplateContents', () => { mockDir.clear(); jest.resetAllMocks(); jest - .spyOn(targetPaths, 'resolveTargetRoot') - .mockImplementation((...args) => mockDir.resolve(...args)); + .spyOn(targetPaths, 'resolveRoot') + .mockImplementation((...args: string[]) => mockDir.resolve(...args)); }); it('should write an empty template', async () => { diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index 8359468ba0..40bbec1ed4 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -29,7 +29,7 @@ export async function writeTemplateContents( template: PortableTemplate, input: PortableTemplateInput, ): Promise<{ targetDir: string }> { - const targetDir = targetPaths.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 168e277fb6..5bf9de64ca 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -39,7 +39,7 @@ export async function collectPortableTemplateInput( ): Promise { const { config, template, prefilledParams } = options; - const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.targetRoot); + const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.resolveRoot()); 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 6d230c14cf..6a683fb31c 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplate.ts @@ -47,7 +47,7 @@ export async function loadPortableTemplate( throw new Error('Remote templates are not supported yet'); } const templateContent = await fs - .readFile(targetPaths.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 c996bc9194..5040904138 100644 --- a/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/modules/new/lib/preparation/loadPortableTemplateConfig.ts @@ -91,7 +91,7 @@ export async function loadPortableTemplateConfig( ): Promise { const { overrides = {} } = options; const pkgPath = - options.packagePath ?? targetPaths.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 3dd3399bd2..6553ad93c9 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -18,8 +18,6 @@ import { Command, OptionValues } from 'commander'; import { runCheck, findOwnPaths } from '@backstage/cli-common'; -const ownPaths = findOwnPaths(__dirname); - function includesAnyOf(hayStack: string[], ...needles: string[]) { for (const needle of needles) { if (hayStack.includes(needle)) { @@ -40,7 +38,7 @@ 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', ownPaths.resolveOwn('config/jest.js')); + 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 ae0882719f..6e8e22c140 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -24,10 +24,13 @@ import { relative as relativePath } from 'node:path'; import { Command, OptionValues } from 'commander'; import { Lockfile, PackageGraph } from '@backstage/cli-node'; -import { runCheck, runOutput, targetPaths, findOwnPaths } from '@backstage/cli-common'; - -const ownPaths = findOwnPaths(__dirname); -import { isChildPath } from '@backstage/cli-common'; +import { + runCheck, + runOutput, + targetPaths, + findOwnPaths, + isChildPath, +} from '@backstage/cli-common'; import { SuccessCache } from '../../../../lib/cache/SuccessCache'; type JestProject = { @@ -65,7 +68,7 @@ interface TestGlobal extends Global { async function readPackageTreeHashes(graph: PackageGraph) { const pkgs = Array.from(graph.values()).map(pkg => ({ ...pkg, - path: relativePath(targetPaths.targetRoot, pkg.dir), + path: relativePath(targetPaths.resolveRoot(), pkg.dir), })); const output = await runOutput([ 'git', @@ -164,7 +167,7 @@ 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', ownPaths.resolveOwn('config/jest.js')); + args.push('--config', findOwnPaths(__dirname).resolve('config/jest.js')); } if (!hasFlags('--passWithNoTests')) { @@ -343,7 +346,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { async filterConfigs(projectConfigs, globalRootConfig) { const cacheEntries = await cache.read(); const lockfile = await Lockfile.load( - targetPaths.resolveTargetRoot('yarn.lock'), + targetPaths.resolveRoot('yarn.lock'), ); const getPackageTreeHash = await readPackageTreeHashes(graph); 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/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index 2133eccc29..45659b4cac 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.resolveRoot(); const argSources = options.targets.map(arg => { if (arg.type === 'url') { diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index c854867de6..4fb5438d70 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -19,12 +19,36 @@ 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'; jest.mock('./lib/tasks'); +jest.mock('@backstage/cli-common', () => { + const pathModule = require('node:path'); + const actual = jest.requireActual('@backstage/cli-common'); + const MOCK_CREATE_APP_ROOT = '/mock/create-app-root'; + const MOCK_TARGET_DIR = '/mock/target-dir'; + const mockOwnPaths = { + resolve: (...paths: string[]) => + pathModule.join(MOCK_CREATE_APP_ROOT, ...paths), + resolveRoot: (...paths: string[]) => + pathModule.join('/mock/monorepo-root', ...paths), + }; + return { + ...actual, + findPaths: jest.fn(), + findOwnPaths: () => mockOwnPaths, + targetPaths: { + resolve: (...paths: string[]) => + pathModule.resolve(MOCK_TARGET_DIR, ...paths), + resolveRoot: (...paths: string[]) => + pathModule.resolve('/mock/target-root', ...paths), + }, + }; +}); + // 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 +88,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 +104,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 +117,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 +136,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..3f63cd0a60 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', @@ -67,19 +65,19 @@ export default async (opts: OptionValues): Promise => { // Pick the built-in template based on the --next flag const builtInTemplate = opts.next - ? paths.resolveOwn('templates/next-app') - : paths.resolveOwn('templates/default-app'); + ? findOwnPaths(__dirname).resolve('templates/next-app') + : findOwnPaths(__dirname).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.resolve(), opts.path) + : resolvePath(targetPaths.resolve(), answers.name); Task.log(); Task.log('Creating the app...'); @@ -102,7 +100,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.resolve(), answers.name); Task.section('Creating a temporary app directory'); const tempDir = await fs.mkdtemp(resolvePath(os.tmpdir(), answers.name)); diff --git a/packages/e2e-test/src/commands/runCommand.ts b/packages/e2e-test/src/commands/runCommand.ts index f0701d0e5d..ca95a2fa3e 100644 --- a/packages/e2e-test/src/commands/runCommand.ts +++ b/packages/e2e-test/src/commands/runCommand.ts @@ -27,12 +27,9 @@ import { waitFor, print } from '../lib/helpers'; import mysql from 'mysql2/promise'; import pgtools from 'pgtools'; -import { findPaths, runOutput, run } from '@backstage/cli-common'; +import { findOwnPaths, runOutput, run } from '@backstage/cli-common'; import { OptionValues } from 'commander'; -// eslint-disable-next-line no-restricted-syntax -const paths = findPaths(__dirname); - const templatePackagePaths = [ 'packages/cli/templates/frontend-plugin/package.json.hbs', 'packages/create-app/templates/default-app/package.json.hbs', @@ -138,7 +135,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { } for (const pkgJsonPath of templatePackagePaths) { - const jsonPath = paths.resolveOwnRoot(pkgJsonPath); + const jsonPath = findOwnPaths(__dirname).resolveRoot(pkgJsonPath); const pkgTemplate = await fs.readFile(jsonPath, 'utf8'); const pkg = JSON.parse( handlebars.compile(pkgTemplate)( @@ -196,7 +193,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 = findOwnPaths(__dirname).resolveRoot('.yarn/patches'); if (await fs.pathExists(yarnPatchesPath)) { print('Copying yarn patches'); await fs.copy(yarnPatchesPath, resolvePath(workspaceDir, '.yarn/patches')); @@ -214,7 +211,10 @@ 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( + findOwnPaths(__dirname).resolveRoot('.yarnrc.yml'), + 'utf8', + ); const yarnRcLines = yarnRc.split(/\r?\n/); const yarnPathLine = yarnRcLines.find(line => line.startsWith('yarnPath:')); if (!yarnPathLine) { @@ -225,8 +225,9 @@ 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 ownPaths = findOwnPaths(__dirname); + const yarnPath = ownPaths.resolveRoot(localYarnPath); + const yarnPluginPath = ownPaths.resolveRoot( localYarnPath, '../../plugins/@yarnpkg/plugin-workspace-tools.cjs', ); @@ -328,7 +329,7 @@ async function createApp( */ async function overrideYarnLockSeed(appDir: string) { const content = await fs.readFile( - paths.resolveOwnRoot('packages/create-app/seed-yarn.lock'), + findOwnPaths(__dirname).resolveRoot('packages/create-app/seed-yarn.lock'), 'utf8', ); const trimmedContent = content diff --git a/packages/repo-tools/src/lib/paths.ts b/packages/repo-tools/src/lib/paths.ts index ccca6f09c9..2e50b687a4 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -14,13 +14,26 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; +import { targetPaths, findOwnPaths } 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); +export const paths = { + get targetDir() { + return targetPaths.resolve(); + }, + get targetRoot() { + return targetPaths.resolveRoot(); + }, + get ownRoot() { + return findOwnPaths(__dirname).resolveRoot(); + }, + resolveTarget: targetPaths.resolve, + resolveTargetRoot: targetPaths.resolveRoot, + resolveOwnRoot: (...p: string[]) => findOwnPaths(__dirname).resolveRoot(...p), +}; /** @internal */ export interface ResolvePackagesOptions { @@ -41,7 +54,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.resolveRoot(), dir)) || isChildPath(dir, path), ); if (!matches) { @@ -57,7 +70,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.resolveRoot(), dir)) || isChildPath(dir, path), ), ); @@ -66,7 +79,7 @@ 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.resolveRoot(), pkg.dir)), ), ); } @@ -76,13 +89,13 @@ export async function resolvePackagePaths( exclude.some( pattern => !new Minimatch(pattern).match( - relativePath(paths.targetRoot, pkg.dir), + relativePath(targetPaths.resolveRoot(), pkg.dir), ), ), ); } - return packages.map(pkg => relativePath(paths.targetRoot, pkg.dir)); + return packages.map(pkg => relativePath(targetPaths.resolveRoot(), pkg.dir)); } /** @internal */ diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 864861828b..511cad0472 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,7 @@ 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'); + return findOwnPaths(__dirname).resolve('dist/embedded-app'); } } diff --git a/packages/yarn-plugin/src/index.test.ts b/packages/yarn-plugin/src/index.test.ts index 688098a626..2b907d7a96 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.resolveRoot(); 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..750e1d5c5e 100644 --- a/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts +++ b/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { findPaths, Paths } from '@backstage/cli-common'; +import { targetPaths } from '@backstage/cli-common'; const setPlatform = (platform: string) => { Object.defineProperty(process, `platform`, { @@ -37,7 +37,7 @@ describe('getWorkspaceRoot', () => { `('platform: $platform', ({ platform, native, portable }) => { let realPlatform: string; let getWorkspaceRoot: () => string; - let mockFindPaths: jest.MockedFunction; + let mockResolveRoot: jest.MockedFunction; beforeEach(() => { realPlatform = process.platform; @@ -45,11 +45,13 @@ describe('getWorkspaceRoot', () => { jest.resetModules(); - mockFindPaths = jest.fn(); + mockResolveRoot = jest.fn(); jest.doMock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), - findPaths: mockFindPaths, + targetPaths: { + resolveRoot: mockResolveRoot, + }, })); getWorkspaceRoot = require('./getWorkspaceRoot').getWorkspaceRoot; @@ -60,9 +62,7 @@ describe('getWorkspaceRoot', () => { }); it('returns an appropriately-formatted workspace root path', () => { - mockFindPaths.mockReturnValue({ - targetRoot: native, - } as Paths); + mockResolveRoot.mockReturnValue(native); expect(getWorkspaceRoot()).toEqual(portable); }); diff --git a/packages/yarn-plugin/src/util/getWorkspaceRoot.ts b/packages/yarn-plugin/src/util/getWorkspaceRoot.ts index d6f3e98e10..9b12abb59d 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.resolveRoot()); }; From 07816d67f30dd7e0aa6d790393c4113761eb4593 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 13:47:49 +0100 Subject: [PATCH 36/62] Address PR review comments - Refactor targetPaths/findOwnPaths to class-based implementations with unified caching and .dir/.rootDir properties alongside resolve methods - Replace jest.mock with jest.spyOn in plugin-manager.test.ts - Remove paths compatibility wrapper from repo-tools, migrate all internal consumers to use targetPaths from @backstage/cli-common directly - Fix changeset package name (@techdocs/cli not @backstage/techdocs-cli) - Add migration examples to cli-common changeset - Update API report for cli-common Signed-off-by: Patrik Oldsberg --- .changeset/cli-common-cached-paths.md | 23 ++ .changeset/migrate-to-target-paths.md | 2 +- .../src/manager/plugin-manager.test.ts | 39 +-- .../src/manager/plugin-manager.ts | 2 +- .../src/schemas/schemas.ts | 2 +- packages/cli-common/report.api.md | 22 ++ packages/cli-common/src/paths.ts | 255 ++++++++++-------- packages/cli-node/src/paths.ts | 8 +- packages/cli/src/lib/cache/SuccessCache.ts | 2 +- .../build/commands/package/build/command.ts | 6 +- .../build/commands/package/start/command.ts | 2 +- .../commands/package/start/startBackend.ts | 2 +- .../commands/package/start/startFrontend.ts | 4 +- .../src/modules/build/commands/repo/build.ts | 2 +- .../src/modules/build/lib/builder/config.ts | 4 +- .../src/modules/build/lib/builder/packager.ts | 4 +- .../build/lib/bundler/hasReactDomClient.ts | 2 +- .../build/lib/bundler/linkWorkspaces.ts | 2 +- .../build/lib/bundler/packageDetection.ts | 2 +- .../src/modules/build/lib/bundler/paths.ts | 6 +- .../src/modules/build/lib/bundler/server.ts | 4 +- .../build/lib/packager/createDistWorkspace.ts | 8 +- .../cli/src/modules/build/lib/role.test.ts | 6 + packages/cli/src/modules/config/lib/config.ts | 4 +- .../cli/src/modules/info/commands/info.ts | 2 +- .../src/modules/lint/commands/package/lint.ts | 4 +- .../src/modules/lint/commands/repo/lint.ts | 6 +- .../maintenance/commands/package/pack.ts | 6 +- .../modules/maintenance/commands/repo/fix.ts | 8 +- .../commands/repo/list-deprecations.ts | 4 +- .../modules/migrate/commands/packageRole.ts | 2 +- .../migrate/commands/versions/bump.test.ts | 6 + .../modules/migrate/commands/versions/bump.ts | 2 +- .../migrate/commands/versions/migrate.test.ts | 6 + .../modules/new/lib/codeowners/codeowners.ts | 2 +- .../collectPortableTemplateInput.ts | 2 +- .../src/modules/test/commands/repo/test.ts | 2 +- .../src/sources/ConfigSources.ts | 2 +- packages/create-app/src/createApp.test.ts | 6 + packages/create-app/src/createApp.ts | 6 +- .../api-reports/createTemporaryTsConfig.ts | 4 +- .../api-reports/generateTypeDeclarations.ts | 6 +- .../api-reports/patchApiReportGeneration.ts | 4 +- .../api-reports/runApiExtraction.ts | 12 +- .../api-reports/buildApiReports.test.ts | 12 +- .../commands/api-reports/buildApiReports.ts | 9 +- .../api-reports/categorizePackageDirs.ts | 6 +- .../cli-reports/runCliExtraction.ts | 6 +- .../api-reports/common/tryRunPrettier.ts | 6 +- .../sql-reports/runSqlExtraction.ts | 12 +- .../commands/knip-reports/knip-extractor.ts | 12 +- .../lint-legacy-backend-exports.ts | 4 +- .../src/commands/package-docs/command.ts | 37 +-- .../src/commands/package-docs/utils.ts | 4 +- .../commands/package/schema/openapi/diff.ts | 8 +- .../commands/package/schema/openapi/fuzz.ts | 6 +- .../package/schema/openapi/generate/client.ts | 6 +- .../package/schema/openapi/generate/server.ts | 12 +- .../commands/package/schema/openapi/init.ts | 6 +- .../src/commands/repo/schema/openapi/diff.ts | 6 +- .../src/commands/repo/schema/openapi/test.ts | 8 +- .../commands/repo/schema/openapi/verify.ts | 4 +- .../repo-tools/src/lib/openapi/helpers.ts | 4 +- packages/repo-tools/src/lib/paths.ts | 28 +- packages/repo-tools/src/lib/runner.ts | 4 +- packages/yarn-plugin/src/index.test.ts | 2 +- .../src/util/getWorkspaceRoot.test.ts | 6 + .../yarn-plugin/src/util/getWorkspaceRoot.ts | 2 +- 68 files changed, 394 insertions(+), 321 deletions(-) diff --git a/.changeset/cli-common-cached-paths.md b/.changeset/cli-common-cached-paths.md index a82a5434b0..6d9ec14297 100644 --- a/.changeset/cli-common-cached-paths.md +++ b/.changeset/cli-common-cached-paths.md @@ -3,3 +3,26 @@ --- 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/migrate-to-target-paths.md b/.changeset/migrate-to-target-paths.md index b3f983bffc..a3c0c0c57e 100644 --- a/.changeset/migrate-to-target-paths.md +++ b/.changeset/migrate-to-target-paths.md @@ -5,7 +5,7 @@ '@backstage/config-loader': patch '@backstage/create-app': patch '@backstage/repo-tools': patch -'@backstage/techdocs-cli': patch +'@techdocs/cli': patch --- Migrated from deprecated `findPaths` to `targetPaths` and `findOwnPaths` from `@backstage/cli-common`. 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 011aae0457..b778e4df6e 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 @@ -40,37 +40,24 @@ import { Logs, MockedLogger, LogContent } from '../__testUtils__/testUtils'; import { PluginScanner } from '../scanner/plugin-scanner'; import { targetPaths } from '@backstage/cli-common'; import { createMockDirectory } from '@backstage/backend-test-utils'; - -jest.mock('@backstage/cli-common', () => { - const path = require('path'); - const actual = jest.requireActual( - '@backstage/cli-common', - ); - const mockRoot = path.resolve(__dirname, '..', '..', '..', '..'); - return { - ...actual, - targetPaths: { - resolve: (...paths: string[]) => path.join(mockRoot, ...paths), - resolveRoot: (...paths: string[]) => path.join(mockRoot, ...paths), - }, - findPaths: (searchDir: string) => ({ - targetRoot: mockRoot, - targetDir: mockRoot, - ownDir: path.dirname(searchDir), - ownRoot: mockRoot, - resolveOwn: (...p: string[]) => path.join(path.dirname(searchDir), ...p), - resolveOwnRoot: (...p: string[]) => path.join(mockRoot, ...p), - resolveTarget: (...p: string[]) => path.join(mockRoot, ...p), - resolveTargetRoot: (...p: string[]) => path.join(mockRoot, ...p), - }), - }; -}); import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; describe('backend-dynamic-feature-service', () => { const mockDir = createMockDirectory(); + beforeAll(() => { + jest + .spyOn(targetPaths, 'resolveRoot') + .mockImplementation((...paths: string[]) => + require('path').resolve(__dirname, '../../../..', ...paths), + ); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + describe('loadPlugins', () => { afterEach(() => { jest.resetModules(); @@ -1069,7 +1056,7 @@ describe('backend-dynamic-feature-service', () => { otherMockDir.resolve('a-dynamic-plugin'), ); expect(mockedModuleLoader.bootstrap).toHaveBeenCalledWith( - targetPaths.resolveRoot(), + 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 5fe4f7241c..b79a796eb9 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts @@ -56,7 +56,7 @@ export class DynamicPluginManager implements DynamicPluginProvider { options: DynamicPluginManagerOptions, ): Promise { /* eslint-disable-next-line no-restricted-syntax */ - const backstageRoot = targetPaths.resolveRoot(); + 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 3a1bc666b0..400f57829a 100644 --- a/packages/backend-dynamic-feature-service/src/schemas/schemas.ts +++ b/packages/backend-dynamic-feature-service/src/schemas/schemas.ts @@ -100,7 +100,7 @@ const dynamicPluginsSchemasServiceFactoryWithOptions = ( config, logger, // eslint-disable-next-line no-restricted-syntax - backstageRoot: targetPaths.resolveRoot(), + backstageRoot: targetPaths.rootDir, preferAlpha: true, }); diff --git a/packages/cli-common/report.api.md b/packages/cli-common/report.api.md index 96475c6bd1..18f2ccb63c 100644 --- a/packages/cli-common/report.api.md +++ b/packages/cli-common/report.api.md @@ -21,12 +21,23 @@ export class ExitCodeError extends CustomErrorBase { } // @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 +79,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/paths.ts b/packages/cli-common/src/paths.ts index 15cdc7b89c..f4fded7cd4 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -33,6 +33,12 @@ export type ResolveFunc = (...paths: string[]) => string; * @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; @@ -46,6 +52,12 @@ export type TargetPaths = { * @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; @@ -98,48 +110,12 @@ export function findRootPath( ); } -// Hierarchical cache for ownDir lookups. When we resolve a searchDir to its -// package root, we also cache every intermediate directory along the way. This -// means sibling directories only need to walk up until they hit a cached ancestor. -const ownDirCache = new Map(); - // Finds the root of a given package export function findOwnDir(searchDir: string) { - const visited: string[] = []; - let dir = searchDir; - - for (let i = 0; i < 1000; i++) { - const cached = ownDirCache.get(dir); - if (cached !== undefined) { - for (const d of visited) { - ownDirCache.set(d, cached); - } - return cached; - } - - visited.push(dir); - - const packagePath = resolvePath(dir, 'package.json'); - if (fs.existsSync(packagePath)) { - for (const d of visited) { - ownDirCache.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}`, - ); + return OwnPathsImpl.findDir(searchDir); } -// 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) { @@ -151,46 +127,131 @@ export function findOwnRootDir(ownDir: string) { return resolvePath(ownDir, '../..'); } -// Cached target path state. Re-resolves when process.cwd() changes. -let cachedTargetCwd: string | undefined; -let cachedTargetDir: string | undefined; -let cachedTargetRoot: string | undefined; +// 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(); -function getTargetDir(): string { - const cwd = process.cwd(); - if (cachedTargetDir !== undefined && cachedTargetCwd === cwd) { - return cachedTargetDir; +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; } - cachedTargetCwd = cwd; - cachedTargetRoot = undefined; - // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency - cachedTargetDir = fs - .realpathSync(cwd) - .replace(/^[a-z]:/, str => str.toLocaleUpperCase('en-US')); - return cachedTargetDir; + + 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); + }; } -function getTargetRoot(): string { - // Ensure targetDir is fresh, which also invalidates targetRoot on cwd change - const targetDir = getTargetDir(); - if (cachedTargetRoot !== undefined) { - return cachedTargetRoot; +class TargetPathsImpl implements TargetPaths { + #cwd: string | undefined; + #dir: string | undefined; + #rootDir: string | undefined; + + get dir(): string { + 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; } - // 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. - cachedTargetRoot = - 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; - return cachedTargetRoot; + + get rootDir(): string { + // 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 => { + return resolvePath(this.dir, ...paths); + }; + + resolveRoot = (...paths: string[]): string => { + return resolvePath(this.rootDir, ...paths); + }; } /** @@ -198,18 +259,8 @@ function getTargetRoot(): string { * for cwd-based path resolution without needing `__dirname`. * * @public - * @example - * - * import { targetPaths } from '\@backstage/cli-common'; - * - * const lockfile = targetPaths.resolveRoot('yarn.lock'); */ -export const targetPaths: TargetPaths = { - resolve: (...paths) => resolvePath(getTargetDir(), ...paths), - resolveRoot: (...paths) => resolvePath(getTargetRoot(), ...paths), -}; - -const ownPathsCache = new Map(); +export const targetPaths: TargetPaths = new TargetPathsImpl(); /** * Find paths relative to the package that the calling code lives in. @@ -219,35 +270,9 @@ const ownPathsCache = new Map(); * subdirectories within the same package share work. * * @public - * @example - * - * import { findOwnPaths } from '\@backstage/cli-common'; - * - * const own = findOwnPaths(__dirname); - * const config = own.resolve('config/jest.js'); */ export function findOwnPaths(searchDir: string): OwnPaths { - const ownDir = findOwnDir(searchDir); - const cached = ownPathsCache.get(ownDir); - if (cached) { - return cached; - } - - let ownRoot = ''; - const getOwnRoot = () => { - if (!ownRoot) { - ownRoot = findOwnRootDir(ownDir); - } - return ownRoot; - }; - - const paths: OwnPaths = { - resolve: (...p) => resolvePath(ownDir, ...p), - resolveRoot: (...p) => resolvePath(getOwnRoot(), ...p), - }; - - ownPathsCache.set(ownDir, paths); - return paths; + return OwnPathsImpl.find(searchDir); } /** @@ -265,16 +290,16 @@ export function findPaths(searchDir: string): Paths { const own = findOwnPaths(searchDir); return { get ownDir() { - return own.resolve(); + return own.dir; }, get ownRoot() { - return own.resolveRoot(); + return own.rootDir; }, get targetDir() { - return targetPaths.resolve(); + return targetPaths.dir; }, get targetRoot() { - return targetPaths.resolveRoot(); + return targetPaths.rootDir; }, resolveOwn: own.resolve, resolveOwnRoot: own.resolveRoot, diff --git a/packages/cli-node/src/paths.ts b/packages/cli-node/src/paths.ts index 57c98ea0a8..47b17c1825 100644 --- a/packages/cli-node/src/paths.ts +++ b/packages/cli-node/src/paths.ts @@ -21,16 +21,16 @@ const ownPaths = findOwnPaths(__dirname); /* eslint-disable-next-line no-restricted-syntax */ export const paths = { get ownDir() { - return ownPaths.resolve(); + return ownPaths.dir; }, get ownRoot() { - return ownPaths.resolveRoot(); + return ownPaths.rootDir; }, get targetDir() { - return targetPaths.resolve(); + return targetPaths.dir; }, get targetRoot() { - return targetPaths.resolveRoot(); + return targetPaths.rootDir; }, resolveOwn: ownPaths.resolve, resolveOwnRoot: ownPaths.resolveRoot, diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index 495baf660c..2dc01593b4 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -32,7 +32,7 @@ export class SuccessCache { * location. */ static trimPaths(input: string) { - return input.replaceAll(targetPaths.resolveRoot(), ''); + return input.replaceAll(targetPaths.rootDir, ''); } constructor(name: string, basePath?: string) { 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 408d7dab52..944be832f0 100644 --- a/packages/cli/src/modules/build/commands/package/build/command.ts +++ b/packages/cli/src/modules/build/commands/package/build/command.ts @@ -47,14 +47,14 @@ export async function command(opts: OptionValues): Promise { if (role === 'frontend') { return buildFrontend({ - targetDir: targetPaths.resolve(), + targetDir: targetPaths.dir, configPaths, writeStats: Boolean(opts.stats), webpack, }); } return buildBackend({ - targetDir: targetPaths.resolve(), + targetDir: targetPaths.dir, configPaths, skipBuildDependencies: Boolean(opts.skipBuildDependencies), minify: Boolean(opts.minify), @@ -77,7 +77,7 @@ export async function command(opts: OptionValues): Promise { if (isModuleFederationRemote) { console.log('Building package as a module federation remote'); return buildFrontend({ - targetDir: targetPaths.resolve(), + targetDir: targetPaths.dir, configPaths: [], writeStats: Boolean(opts.stats), isModuleFederationRemote, 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 9bc0bfc841..c1abd7ed14 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -25,7 +25,7 @@ export async function command(opts: OptionValues): Promise { await startPackage({ role: await findRoleFromCommand(opts), entrypoint: opts.entrypoint, - targetDir: targetPaths.resolve(), + 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 3ea1e9bbe9..a36a93b8ff 100644 --- a/packages/cli/src/modules/build/commands/package/start/startBackend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startBackend.ts @@ -44,7 +44,7 @@ export async function startBackend(options: StartBackendOptions) { export async function startBackendPlugin(options: StartBackendOptions) { const hasDevIndexEntry = await fs.pathExists( - resolvePath(options.targetDir ?? targetPaths.resolve(), '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 413ce6b752..c81fd2fd66 100644 --- a/packages/cli/src/modules/build/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startFrontend.ts @@ -39,7 +39,7 @@ interface StartAppOptions { export async function startFrontend(options: StartAppOptions) { const packageJson = (await readJson( - resolvePath(options.targetDir ?? targetPaths.resolve(), 'package.json'), + resolvePath(options.targetDir ?? targetPaths.dir, 'package.json'), )) as BackstagePackageJson; if (!hasReactDomClient()) { @@ -59,7 +59,7 @@ export async function startFrontend(options: StartAppOptions) { moduleFederationRemote: options.isModuleFederationRemote ? await getModuleFederationRemoteOptions( packageJson, - resolvePath(targetPaths.resolve()), + 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 8b1391ecf9..dd65e926b2 100644 --- a/packages/cli/src/modules/build/commands/repo/build.ts +++ b/packages/cli/src/modules/build/commands/repo/build.ts @@ -90,7 +90,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { targetDir: pkg.dir, packageJson: pkg.packageJson, outputs, - logPrefix: `${chalk.cyan(relativePath(targetPaths.resolveRoot(), pkg.dir))}: `, + logPrefix: `${chalk.cyan(relativePath(targetPaths.rootDir, pkg.dir))}: `, workspacePackages: packages, minify: opts.minify ?? buildOptions.minify, }; diff --git a/packages/cli/src/modules/build/lib/builder/config.ts b/packages/cli/src/modules/build/lib/builder/config.ts index 08b8221a77..4123d2ccf3 100644 --- a/packages/cli/src/modules/build/lib/builder/config.ts +++ b/packages/cli/src/modules/build/lib/builder/config.ts @@ -117,7 +117,7 @@ export async function makeRollupConfigs( options: BuildOptions, ): Promise { const configs = new Array(); - const targetDir = options.targetDir ?? targetPaths.resolve(); + const targetDir = options.targetDir ?? targetPaths.dir; let targetPkg = options.packageJson; if (!targetPkg) { @@ -287,7 +287,7 @@ export async function makeRollupConfigs( e.name, targetPaths.resolveRoot( 'dist-types', - relativePath(targetPaths.resolveRoot(), 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 527fbbba0e..cee6d0a11c 100644 --- a/packages/cli/src/modules/build/lib/builder/packager.ts +++ b/packages/cli/src/modules/build/lib/builder/packager.ts @@ -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(targetPaths.resolve(), error.id); + const path = relativePath(targetPaths.dir, error.id); const loc = chalk.cyan(`${path}:${line}:${column}`); if (text === 'Unexpected "<"' && error.id.endsWith('.js')) { @@ -107,7 +107,7 @@ export const buildPackage = async (options: BuildOptions) => { const rollupConfigs = await makeRollupConfigs(options); - const targetDir = options.targetDir ?? targetPaths.resolve(); + const targetDir = options.targetDir ?? targetPaths.dir; await fs.remove(resolvePath(targetDir, 'dist')); const buildTasks = rollupConfigs.map(rollupBuild); diff --git a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts index 6acd96f8c1..0a60840047 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -20,7 +20,7 @@ import { targetPaths } from '@backstage/cli-common'; export function hasReactDomClient() { try { require.resolve('react-dom/client', { - paths: [targetPaths.resolve()], + 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 935e14e85a..10a2e7d209 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -53,7 +53,7 @@ export async function createWorkspaceLinkingPlugins( /^react(?:-router)?(?:-dom)?$/, resource => { if (!relativePath(linkedRoot.dir, resource.context).startsWith('..')) { - resource.context = targetPaths.resolve(); + resource.context = targetPaths.dir; } }, ), diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index 3f361819f3..cb2c3f588f 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -147,7 +147,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( - targetPaths.resolveRoot(), + 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 d0d56e6396..4e79f77884 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -21,14 +21,14 @@ import { targetPaths, findOwnPaths } from '@backstage/cli-common'; export type BundlingPathsOptions = { // bundle entrypoint, e.g. 'src/index' entry: string; - // Target directory, defaulting to targetPaths.resolve() + // Target directory, defaulting to targetPaths.dir targetDir?: string; // Relative dist directory, defaulting to 'dist' dist?: string; }; export function resolveBundlingPaths(options: BundlingPathsOptions) { - const { entry, targetDir = targetPaths.resolve() } = options; + const { entry, targetDir = targetPaths.dir } = options; const resolveTargetModule = (pathString: string) => { for (const ext of ['mjs', 'js', 'ts', 'tsx', 'jsx']) { @@ -70,7 +70,7 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetTsConfig: targetPaths.resolveRoot('tsconfig.json'), targetPackageJson: resolvePath(targetDir, 'package.json'), rootNodeModules: targetPaths.resolveRoot('node_modules'), - root: targetPaths.resolveRoot(), + 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 27e0cbd034..57d6bed052 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -54,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 ?? targetPaths.resolve(), 'package.json'), + resolvePath(options.targetDir ?? targetPaths.dir, 'package.json'), ); let devServer: RspackDevServer | undefined = undefined; @@ -272,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: [targetPaths.resolveRoot()], + paths: [targetPaths.rootDir], }); const reactPkg = require(reactPkgPath); if (reactPkg.version.startsWith('16.')) { diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index 6d55fdac0f..e1adcd6c20 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -211,7 +211,7 @@ export async function createDistWorkspace( targetDir: pkg.dir, packageJson: pkg.packageJson, outputs: outputs, - logPrefix: `${chalk.cyan(relativePath(targetPaths.resolveRoot(), pkg.dir))}: `, + logPrefix: `${chalk.cyan(relativePath(targetPaths.rootDir, pkg.dir))}: `, minify: options.minify, workspacePackages: packages, }); @@ -252,7 +252,7 @@ export async function createDistWorkspace( if (options.skeleton) { const skeletonFiles = targets .map(target => { - const dir = relativePath(targetPaths.resolveRoot(), target.dir); + const dir = relativePath(targetPaths.rootDir, target.dir); return joinPath(dir, 'package.json'); }) .sort(); @@ -301,7 +301,7 @@ async function moveToDistWorkspace( fastPackPackages.map(async target => { console.log(`Moving ${target.name} into dist workspace`); - const outputDir = relativePath(targetPaths.resolveRoot(), target.dir); + const outputDir = relativePath(targetPaths.rootDir, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await productionPack({ packageDir: target.dir, @@ -321,7 +321,7 @@ async function moveToDistWorkspace( cwd: target.dir, }).waitForExit(); - const outputDir = relativePath(targetPaths.resolveRoot(), target.dir); + const outputDir = relativePath(targetPaths.rootDir, target.dir); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); await fs.ensureDir(absoluteOutputPath); diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index 1e26f78f33..76b202ae98 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -23,6 +23,12 @@ const mockDir = createMockDirectory(); jest.mock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), targetPaths: { + get dir() { + return mockDir.path; + }, + get rootDir() { + return mockDir.path; + }, resolve: (...args: string[]) => mockDir.resolve(...args), resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, diff --git a/packages/cli/src/modules/config/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts index b819d1da7b..1d920eb31e 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -35,7 +35,7 @@ type Options = { }; export async function loadCliConfig(options: Options) { - const targetDir = options.targetDir ?? targetPaths.resolve(); + const targetDir = options.targetDir ?? targetPaths.dir; // Consider all packages in the monorepo when loading in config const { packages } = await getPackages(targetDir); @@ -74,7 +74,7 @@ export async function loadCliConfig(options: Options) { ? async name => process.env[name] || 'x' : undefined, watch: Boolean(options.watch), - rootDir: targetPaths.resolveRoot(), + rootDir: targetPaths.rootDir, argv: options.args.flatMap(t => ['--config', resolvePath(targetDir, t)]), }); diff --git a/packages/cli/src/modules/info/commands/info.ts b/packages/cli/src/modules/info/commands/info.ts index b0ce28fb7d..6fcf78cc84 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -84,7 +84,7 @@ export default async (options: InfoOptions) => { const lockfilePath = targetPaths.resolveRoot('yarn.lock'); const lockfile = await Lockfile.load(lockfilePath); - const targetPath = targetPaths.resolveRoot(); + 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 f75937f6d1..0a453ac71a 100644 --- a/packages/cli/src/modules/lint/commands/package/lint.ts +++ b/packages/cli/src/modules/lint/commands/package/lint.ts @@ -22,7 +22,7 @@ import { ESLint } from 'eslint'; export default async (directories: string[], opts: OptionValues) => { const eslint = new ESLint({ - cwd: targetPaths.resolve(), + cwd: targetPaths.dir, fix: opts.fix, extensions: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'], }); @@ -48,7 +48,7 @@ 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(targetPaths.resolveRoot()); + process.chdir(targetPaths.rootDir); } const resultText = await formatter.format(results); diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 3bdb8aae97..dafcff45c6 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -63,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(targetPaths.resolveRoot()); + process.chdir(targetPaths.rootDir); } // Make sure lint output is colored unless the user explicitly disabled it @@ -78,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(targetPaths.resolveRoot(), pkg.dir), + relativeDir: relativePath(targetPaths.rootDir, pkg.dir), lintOptions, parentHash: undefined, }; @@ -114,7 +114,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { shouldCache: Boolean(cacheContext), maxWarnings: opts.maxWarnings ?? -1, successCache: cacheContext?.entries, - rootDir: targetPaths.resolveRoot(), + rootDir: targetPaths.rootDir, }, workerFactory: async ({ fix, diff --git a/packages/cli/src/modules/maintenance/commands/package/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts index fd4c9dc162..e5e176d17e 100644 --- a/packages/cli/src/modules/maintenance/commands/package/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -26,16 +26,16 @@ import { createTypeDistProject } from '../../../../lib/typeDistProject'; export const pre = async () => { publishPreflightCheck({ - dir: targetPaths.resolve(), + dir: targetPaths.dir, packageJson: await fs.readJson(targetPaths.resolve('package.json')), }); await productionPack({ - packageDir: targetPaths.resolve(), + packageDir: targetPaths.dir, featureDetectionProject: await createTypeDistProject(), }); }; export const post = async () => { - await revertProductionPack(targetPaths.resolve()); + await revertProductionPack(targetPaths.dir); }; diff --git a/packages/cli/src/modules/maintenance/commands/repo/fix.ts b/packages/cli/src/modules/maintenance/commands/repo/fix.ts index 973436da97..073cb69ea1 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -230,7 +230,7 @@ export function createRepositoryFieldFixer() { return (pkg: FixablePackage) => { const expectedPath = posix.join( rootDir, - relativePath(targetPaths.resolveRoot(), pkg.dir), + relativePath(targetPaths.rootDir, pkg.dir), ); const repoField = pkg.packageJson.repository; @@ -319,7 +319,7 @@ export function fixPluginId(pkg: FixablePackage) { role === 'backend-plugin-module') ) { const path = relativePath( - targetPaths.resolveRoot(), + 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}"`; @@ -415,7 +415,7 @@ export function fixPluginPackages( return; } const path = relativePath( - targetPaths.resolveRoot(), + targetPaths.rootDir, resolvePath(pkg.dir, 'package.json'), ); const suggestedRole = @@ -464,7 +464,7 @@ export function fixPeerModules(pkg: FixablePackage) { } const packagePath = relativePath( - targetPaths.resolveRoot(), + 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 5f80330247..f473e55ce6 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -26,7 +26,7 @@ export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); const eslint = new ESLint({ - cwd: targetPaths.resolve(), + cwd: targetPaths.dir, overrideConfig: { plugins: ['deprecation'], rules: { @@ -53,7 +53,7 @@ export async function command(opts: OptionValues) { continue; } - const path = relativePath(targetPaths.resolveRoot(), 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 878d69a312..32e20f10eb 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -22,7 +22,7 @@ import { targetPaths } from '@backstage/cli-common'; export default async () => { - const { packages } = await getPackages(targetPaths.resolve()); + 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 8f7ac2577b..eafe141e57 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -65,6 +65,12 @@ jest.mock('@backstage/cli-common', () => { return { ...actual, targetPaths: { + get dir() { + return mockDir.path; + }, + get rootDir() { + return mockDir.path; + }, resolve: (...args: string[]) => mockDir.resolve(...args), resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index c508babb05..ff8852de71 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -141,7 +141,7 @@ export default async (opts: OptionValues) => { } // First we discover all Backstage dependencies within our own repo - const dependencyMap = await mapDependencies(targetPaths.resolve(), 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(); 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 75361b0a07..74ba9ae975 100644 --- a/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts @@ -38,6 +38,12 @@ jest.mock('@backstage/cli-common', () => { return { ...actual, targetPaths: { + get dir() { + return mockDir.path; + }, + get rootDir() { + return mockDir.path; + }, resolve: (...args: string[]) => mockDir.resolve(...args), resolveRoot: (...args: string[]) => mockDir.resolve(...args), }, diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index 7842acaaa9..d8e3d0c02f 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -83,7 +83,7 @@ export async function addCodeownersEntry( let filePath = codeownersFilePath; if (!filePath) { - filePath = await getCodeownersFilePath(targetPaths.resolveRoot()); + filePath = await getCodeownersFilePath(targetPaths.rootDir); if (!filePath) { return false; } diff --git a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts index 5bf9de64ca..7279801d62 100644 --- a/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/modules/new/lib/preparation/collectPortableTemplateInput.ts @@ -39,7 +39,7 @@ export async function collectPortableTemplateInput( ): Promise { const { config, template, prefilledParams } = options; - const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.resolveRoot()); + const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.rootDir); const prompts = getPromptsForRole(template.role); diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index 6e8e22c140..46af4e6e4d 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -68,7 +68,7 @@ interface TestGlobal extends Global { async function readPackageTreeHashes(graph: PackageGraph) { const pkgs = Array.from(graph.values()).map(pkg => ({ ...pkg, - path: relativePath(targetPaths.resolveRoot(), pkg.dir), + path: relativePath(targetPaths.rootDir, pkg.dir), })); const output = await runOutput([ 'git', diff --git a/packages/config-loader/src/sources/ConfigSources.ts b/packages/config-loader/src/sources/ConfigSources.ts index 45659b4cac..153da69dbd 100644 --- a/packages/config-loader/src/sources/ConfigSources.ts +++ b/packages/config-loader/src/sources/ConfigSources.ts @@ -157,7 +157,7 @@ export class ConfigSources { static defaultForTargets( options: ConfigSourcesDefaultForTargetsOptions, ): ConfigSource { - const rootDir = options.rootDir ?? targetPaths.resolveRoot(); + const rootDir = options.rootDir ?? targetPaths.rootDir; const argSources = options.targets.map(arg => { if (arg.type === 'url') { diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index 4fb5438d70..56dded39ee 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -41,6 +41,12 @@ jest.mock('@backstage/cli-common', () => { findPaths: jest.fn(), findOwnPaths: () => mockOwnPaths, targetPaths: { + get dir() { + return MOCK_TARGET_DIR; + }, + get rootDir() { + return '/mock/target-root'; + }, resolve: (...paths: string[]) => pathModule.resolve(MOCK_TARGET_DIR, ...paths), resolveRoot: (...paths: string[]) => diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index 3f63cd0a60..9b09f59904 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -76,8 +76,8 @@ export default async (opts: OptionValues): Promise => { // Use `--path` argument as application directory when specified, otherwise // create a directory using `answers.name` const appDir = opts.path - ? resolvePath(targetPaths.resolve(), opts.path) - : resolvePath(targetPaths.resolve(), answers.name); + ? resolvePath(targetPaths.dir, opts.path) + : resolvePath(targetPaths.dir, answers.name); Task.log(); Task.log('Creating the app...'); @@ -100,7 +100,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(targetPaths.resolve(), 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/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.ts b/packages/repo-tools/src/commands/api-reports/api-reports/runApiExtraction.ts index da8278f9ad..89b87b9a0b 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,11 +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( +const tmpDir = targetPaths.resolveRoot( './node_modules/.cache/api-extractor', ); @@ -100,7 +100,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,7 +143,7 @@ export async function runApiExtraction({ // inspected. const allDistTypesEntryPointPaths = allEntryPoints.map( ({ packageDir, distTypesPath }) => { - return cliPaths.resolveTargetRoot( + return targetPaths.resolveRoot( './dist-types', packageDir, distTypesPath, @@ -172,8 +172,8 @@ export async function runApiExtraction({ ? allowWarnings.some(aw => aw === packageDir || minimatch(packageDir, aw)) : allowWarnings; - const projectFolder = cliPaths.resolveTargetRoot(packageDir); - const packageFolder = cliPaths.resolveTargetRoot( + const projectFolder = targetPaths.resolveRoot(packageDir); + const packageFolder = targetPaths.resolveRoot( './dist-types', packageDir, ); 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..000ef11cac 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 { targetPaths } from '@backstage/cli-common'; import { categorizePackageDirs } from './categorizePackageDirs'; @@ -51,14 +51,12 @@ jest.mock('./categorizePackageDirs', () => ({ }), })); -const projectPaths = pathsLib.paths; - const mockDir = createMockDirectory(); -jest.spyOn(projectPaths, 'targetRoot', 'get').mockReturnValue(mockDir.path); +jest.spyOn(targetPaths, 'rootDir', 'get').mockReturnValue(mockDir.path); jest - .spyOn(projectPaths, 'resolveTargetRoot') - .mockImplementation((...path) => mockDir.resolve(...path)); + .spyOn(targetPaths, 'resolveRoot') + .mockImplementation((...path: string[]) => mockDir.resolve(...path)); jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ { dir: normalize(mockDir.resolve('packages/package-a')), @@ -85,7 +83,7 @@ jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ describe('buildApiReports', () => { beforeEach(() => { mockDir.setContent({ - [projectPaths.targetRoot]: { + [targetPaths.rootDir]: { 'package.json': JSON.stringify({ workspaces: { packages: ['packages/*', 'plugins/*'] }, }), diff --git a/packages/repo-tools/src/commands/api-reports/buildApiReports.ts b/packages/repo-tools/src/commands/api-reports/buildApiReports.ts index 74b110236f..87b3f62a6c 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,7 +38,7 @@ type Options = { } & OptionValues; export async function buildApiReports(paths: string[] = [], opts: Options) { - const tmpDir = cliPaths.resolveTargetRoot( + const tmpDir = targetPaths.resolveRoot( './node_modules/.cache/api-extractor', ); @@ -73,7 +74,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 +117,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..7dfaa64524 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; @@ -46,7 +46,7 @@ export async function categorizePackageDirs(packageDirs: string[]) { return; // Ignore packages without roles } if ( - await fs.pathExists(cliPaths.resolveTargetRoot(dir, 'migrations')) + await fs.pathExists(targetPaths.resolveRoot(dir, 'migrations')) ) { sqlPackageDirs.push(dir); } 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..13a0603e41 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.`); @@ -150,7 +151,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { limit(async () => { const pkgJson = JSON.parse( await readFile( - cliPaths.resolveTargetRoot(pkg, 'package.json'), + targetPaths.resolveRoot(pkg, 'package.json'), 'utf-8', ), ); @@ -173,7 +174,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { if (success) { await cache.write( pkg, - cliPaths.resolveTargetRoot(`dist-types`, pkg), + targetPaths.resolveRoot(`dist-types`, pkg), ); } } catch (e) { @@ -187,7 +188,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 +212,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 +221,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..41720f8055 100644 --- a/packages/repo-tools/src/commands/package-docs/utils.ts +++ b/packages/repo-tools/src/commands/package-docs/utils.ts @@ -14,11 +14,11 @@ * 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'); + 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..17033d881a 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, ); @@ -95,7 +95,7 @@ async function generate( signal: abortSignal?.signal, }); - const prettier = cliPaths.resolveTargetRoot('node_modules/.bin/prettier'); + const prettier = targetPaths.resolveRoot('node_modules/.bin/prettier'); if (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..88c6df781a 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,9 @@ export const createOpenApiRouter = async ( ); await exec(`yarn backstage-cli package lint`, ['--fix', tsPath, indexFile]); - if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { + if (await targetPaths.resolveRoot('node_modules/.bin/prettier')) { await exec(`yarn prettier`, ['--write', tsPath, indexFile], { - cwd: cliPaths.targetRoot, + cwd: targetPaths.rootDir, }); } } @@ -150,7 +150,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..558a9a7387 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: @@ -64,7 +64,7 @@ capture: ).join(' ')} `, ); - if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) { + if (await 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..123a1182ea 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,9 @@ async function test( let opticLocation = ''; try { opticLocation = ( - await exec(`yarn bin optic`, [], { cwd: cliPaths.ownRoot }) + await exec(`yarn bin optic`, [], { + cwd: findOwnPaths(__dirname).rootDir, + }) ).stdout as string; } catch (err) { throw new Error( @@ -79,7 +81,7 @@ async function test( throw err; } if ( - (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) && + (await 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 2e50b687a4..3f1c5ce3f4 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -14,27 +14,11 @@ * limitations under the License. */ -import { targetPaths, findOwnPaths } 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 = { - get targetDir() { - return targetPaths.resolve(); - }, - get targetRoot() { - return targetPaths.resolveRoot(); - }, - get ownRoot() { - return findOwnPaths(__dirname).resolveRoot(); - }, - resolveTarget: targetPaths.resolve, - resolveTargetRoot: targetPaths.resolveRoot, - resolveOwnRoot: (...p: string[]) => findOwnPaths(__dirname).resolveRoot(...p), -}; - /** @internal */ export interface ResolvePackagesOptions { paths?: string[]; @@ -54,7 +38,7 @@ export async function resolvePackagePaths( for (const path of providedPaths) { const matches = packages.some( ({ dir }) => - new Minimatch(path).match(relativePath(targetPaths.resolveRoot(), dir)) || + new Minimatch(path).match(relativePath(targetPaths.rootDir, dir)) || isChildPath(dir, path), ); if (!matches) { @@ -70,7 +54,7 @@ export async function resolvePackagePaths( packages = packages.filter(({ dir }) => providedPaths.some( path => - new Minimatch(path).match(relativePath(targetPaths.resolveRoot(), dir)) || + new Minimatch(path).match(relativePath(targetPaths.rootDir, dir)) || isChildPath(dir, path), ), ); @@ -79,7 +63,7 @@ export async function resolvePackagePaths( if (include) { packages = packages.filter(pkg => include.some(pattern => - new Minimatch(pattern).match(relativePath(targetPaths.resolveRoot(), pkg.dir)), + new Minimatch(pattern).match(relativePath(targetPaths.rootDir, pkg.dir)), ), ); } @@ -89,13 +73,13 @@ export async function resolvePackagePaths( exclude.some( pattern => !new Minimatch(pattern).match( - relativePath(targetPaths.resolveRoot(), pkg.dir), + relativePath(targetPaths.rootDir, pkg.dir), ), ), ); } - return packages.map(pkg => relativePath(targetPaths.resolveRoot(), 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/yarn-plugin/src/index.test.ts b/packages/yarn-plugin/src/index.test.ts index 2b907d7a96..4acd6a446f 100644 --- a/packages/yarn-plugin/src/index.test.ts +++ b/packages/yarn-plugin/src/index.test.ts @@ -86,7 +86,7 @@ describe('Backstage yarn plugin', () => { let initialLockFileContent: string | undefined; beforeAll(async () => { - const targetRoot = targetPaths.resolveRoot(); + 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 750e1d5c5e..0f44429707 100644 --- a/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts +++ b/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts @@ -50,6 +50,12 @@ describe('getWorkspaceRoot', () => { jest.doMock('@backstage/cli-common', () => ({ ...jest.requireActual('@backstage/cli-common'), targetPaths: { + get dir() { + return mockResolveRoot(); + }, + get rootDir() { + return mockResolveRoot(); + }, resolveRoot: mockResolveRoot, }, })); diff --git a/packages/yarn-plugin/src/util/getWorkspaceRoot.ts b/packages/yarn-plugin/src/util/getWorkspaceRoot.ts index 9b12abb59d..57e03daabe 100644 --- a/packages/yarn-plugin/src/util/getWorkspaceRoot.ts +++ b/packages/yarn-plugin/src/util/getWorkspaceRoot.ts @@ -18,5 +18,5 @@ import { npath } from '@yarnpkg/fslib'; import { targetPaths } from '@backstage/cli-common'; export const getWorkspaceRoot = () => { - return npath.toPortablePath(targetPaths.resolveRoot()); + return npath.toPortablePath(targetPaths.rootDir); }; From fc03fa6ab2e2f0c610285bafefd600435343e7a6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 13:59:17 +0100 Subject: [PATCH 37/62] Fix backend package.json reference to search-backend-module-explore Signed-off-by: Patrik Oldsberg --- packages/backend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 23b7c17417..fee2734e6e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -68,8 +68,8 @@ "@opentelemetry/auto-instrumentations-node": "^0.67.0", "@opentelemetry/exporter-prometheus": "^0.211.0", "@opentelemetry/sdk-node": "^0.211.0", - "example-app": "link:../app", - "@backstage-community/plugin-search-backend-module-explore": "workspace:^" + "@backstage/plugin-search-backend-module-explore": "workspace:^", + "example-app": "link:../app" }, "devDependencies": { "@backstage/cli": "workspace:^" From 6fa63d411f9485a5f38be3be5a2c053b77d9c0cf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 14:15:27 +0100 Subject: [PATCH 38/62] Fix prettier formatting Signed-off-by: Patrik Oldsberg --- packages/cli/src/lib/cache/SuccessCache.ts | 1 - packages/cli/src/lib/typeDistProject.ts | 1 - packages/cli/src/lib/yarnPlugin.ts | 1 - .../build/commands/package/start/command.ts | 1 - .../src/modules/build/commands/repo/start.test.ts | 1 - .../build/lib/bundler/hasReactDomClient.ts | 1 - .../modules/build/lib/bundler/linkWorkspaces.ts | 1 - .../modules/build/lib/bundler/packageDetection.ts | 1 - .../cli/src/modules/build/lib/bundler/paths.ts | 4 +++- .../build/lib/packager/createDistWorkspace.ts | 4 +++- .../modules/maintenance/commands/package/clean.ts | 1 - .../modules/maintenance/commands/repo/clean.ts | 1 - .../commands/repo/list-deprecations.ts | 1 - .../src/modules/migrate/commands/packageRole.ts | 1 - .../src/modules/migrate/commands/versions/bump.ts | 7 +++++-- .../src/modules/new/lib/codeowners/codeowners.ts | 1 - .../lib/execution/writeTemplateContents.test.ts | 1 - .../new/lib/execution/writeTemplateContents.ts | 2 -- .../api-reports/api-reports/runApiExtraction.ts | 15 +++------------ .../src/commands/api-reports/buildApiReports.ts | 4 +--- .../commands/api-reports/categorizePackageDirs.ts | 4 +--- .../src/commands/package-docs/command.ts | 10 ++-------- .../repo-tools/src/commands/package-docs/utils.ts | 5 ++++- packages/repo-tools/src/lib/paths.ts | 4 +++- 24 files changed, 25 insertions(+), 48 deletions(-) diff --git a/packages/cli/src/lib/cache/SuccessCache.ts b/packages/cli/src/lib/cache/SuccessCache.ts index 2dc01593b4..8131a469a4 100644 --- a/packages/cli/src/lib/cache/SuccessCache.ts +++ b/packages/cli/src/lib/cache/SuccessCache.ts @@ -18,7 +18,6 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'node:path'; import { targetPaths } from '@backstage/cli-common'; - const DEFAULT_CACHE_BASE_PATH = 'node_modules/.cache/backstage-cli'; const CACHE_MAX_AGE_MS = 7 * 24 * 3600_000; diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index 11a0019490..e9cc96d988 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -22,7 +22,6 @@ import { resolve as resolvePath } from 'node:path'; import { Project, SourceFile, SyntaxKind, ts, Type } from 'ts-morph'; import { targetPaths } from '@backstage/cli-common'; - export const createTypeDistProject = async () => { return new Project({ tsConfigFilePath: targetPaths.resolveRoot('tsconfig.json'), diff --git a/packages/cli/src/lib/yarnPlugin.ts b/packages/cli/src/lib/yarnPlugin.ts index fdef27e07f..0390345651 100644 --- a/packages/cli/src/lib/yarnPlugin.ts +++ b/packages/cli/src/lib/yarnPlugin.ts @@ -19,7 +19,6 @@ import yaml from 'yaml'; import z from 'zod'; import { targetPaths } from '@backstage/cli-common'; - const yarnRcSchema = z.object({ plugins: z .array( 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 c1abd7ed14..18f06ab0d2 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -20,7 +20,6 @@ import { resolveLinkedWorkspace } from './resolveLinkedWorkspace'; import { findRoleFromCommand } from '../../../lib/role'; import { targetPaths } from '@backstage/cli-common'; - export async function command(opts: OptionValues): Promise { await startPackage({ role: await findRoleFromCommand(opts), 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 4cb3449e12..54414b7e90 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -19,7 +19,6 @@ import { findTargetPackages } from './start'; import { posix } from 'node:path'; import { targetPaths } from '@backstage/cli-common'; - const mocks = { app: { packageJson: { diff --git a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts index 0a60840047..9dfc3fef5f 100644 --- a/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts +++ b/packages/cli/src/modules/build/lib/bundler/hasReactDomClient.ts @@ -16,7 +16,6 @@ import { targetPaths } from '@backstage/cli-common'; - export function hasReactDomClient() { try { require.resolve('react-dom/client', { diff --git a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts index 10a2e7d209..f724e444b4 100644 --- a/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts +++ b/packages/cli/src/modules/build/lib/bundler/linkWorkspaces.ts @@ -19,7 +19,6 @@ import { getPackages } from '@manypkg/get-packages'; import { rspack } from '@rspack/core'; import { targetPaths } from '@backstage/cli-common'; - /** * This returns of collection of plugins that links a separate workspace into * the target one. Any packages that are present in the linked workspaces will diff --git a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts index cb2c3f588f..5b4837a133 100644 --- a/packages/cli/src/modules/build/lib/bundler/packageDetection.ts +++ b/packages/cli/src/modules/build/lib/bundler/packageDetection.ts @@ -22,7 +22,6 @@ import PQueue from 'p-queue'; import { dirname, join as joinPath, resolve as resolvePath } from 'node:path'; import { targetPaths } from '@backstage/cli-common'; - const DETECTED_MODULES_MODULE_NAME = '__backstage-autodetected-plugins__'; interface PackageDetectionConfig { diff --git a/packages/cli/src/modules/build/lib/bundler/paths.ts b/packages/cli/src/modules/build/lib/bundler/paths.ts index 4e79f77884..2b65052550 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -49,7 +49,9 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { } else { targetHtml = resolvePath(targetDir, `${entry}.html`); if (!fs.pathExistsSync(targetHtml)) { - targetHtml = findOwnPaths(__dirname).resolve('templates/serve_index.html'); + targetHtml = findOwnPaths(__dirname).resolve( + 'templates/serve_index.html', + ); } } diff --git a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts index e1adcd6c20..50fb0f4e31 100644 --- a/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts +++ b/packages/cli/src/modules/build/lib/packager/createDistWorkspace.ts @@ -211,7 +211,9 @@ export async function createDistWorkspace( targetDir: pkg.dir, packageJson: pkg.packageJson, outputs: outputs, - logPrefix: `${chalk.cyan(relativePath(targetPaths.rootDir, pkg.dir))}: `, + logPrefix: `${chalk.cyan( + relativePath(targetPaths.rootDir, pkg.dir), + )}: `, minify: options.minify, workspacePackages: packages, }); diff --git a/packages/cli/src/modules/maintenance/commands/package/clean.ts b/packages/cli/src/modules/maintenance/commands/package/clean.ts index 74c6761a50..70d7ea3771 100644 --- a/packages/cli/src/modules/maintenance/commands/package/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -17,7 +17,6 @@ import fs from 'fs-extra'; import { targetPaths } from '@backstage/cli-common'; - export default async function clean() { await fs.remove(targetPaths.resolve('dist')); await fs.remove(targetPaths.resolve('dist-types')); diff --git a/packages/cli/src/modules/maintenance/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts index 00f45ad967..28b123fa9e 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -20,7 +20,6 @@ import { PackageGraph } from '@backstage/cli-node'; import { run, targetPaths } from '@backstage/cli-common'; - export async function command(): Promise { const packages = await PackageGraph.listTargetPackages(); 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 f473e55ce6..f4114838a1 100644 --- a/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -21,7 +21,6 @@ import { relative as relativePath } from 'node:path'; import { PackageGraph } from '@backstage/cli-node'; import { targetPaths } from '@backstage/cli-common'; - export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); diff --git a/packages/cli/src/modules/migrate/commands/packageRole.ts b/packages/cli/src/modules/migrate/commands/packageRole.ts index 32e20f10eb..6b422c375e 100644 --- a/packages/cli/src/modules/migrate/commands/packageRole.ts +++ b/packages/cli/src/modules/migrate/commands/packageRole.ts @@ -20,7 +20,6 @@ import { getPackages } from '@manypkg/get-packages'; import { PackageRoles } from '@backstage/cli-node'; import { targetPaths } from '@backstage/cli-common'; - export default async () => { const { packages } = await getPackages(targetPaths.dir); diff --git a/packages/cli/src/modules/migrate/commands/versions/bump.ts b/packages/cli/src/modules/migrate/commands/versions/bump.ts index ff8852de71..4283028216 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.ts @@ -13,8 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { BACKSTAGE_JSON, bootstrapEnvProxyAgents, targetPaths } from '@backstage/cli-common'; - +import { + BACKSTAGE_JSON, + bootstrapEnvProxyAgents, + targetPaths, +} from '@backstage/cli-common'; bootstrapEnvProxyAgents(); diff --git a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts index d8e3d0c02f..c0cddba126 100644 --- a/packages/cli/src/modules/new/lib/codeowners/codeowners.ts +++ b/packages/cli/src/modules/new/lib/codeowners/codeowners.ts @@ -18,7 +18,6 @@ import fs from 'fs-extra'; import path from 'node:path'; import { targetPaths } from '@backstage/cli-common'; - const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; const EMAIL_RE = /^[^@]+@[-.\w]+\.[-\w]+$/i; 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 e991d45b51..768f46e20e 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts @@ -19,7 +19,6 @@ import { writeTemplateContents } from './writeTemplateContents'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { targetPaths } from '@backstage/cli-common'; - const baseConfig = { version: '0.1.0', license: 'Apache-2.0', diff --git a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts index 40bbec1ed4..619a6fc3f2 100644 --- a/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts +++ b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.ts @@ -17,14 +17,12 @@ import fs from 'fs-extra'; import { dirname, resolve as resolvePath } from 'node:path'; - 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, targetPaths } from '@backstage/cli-common'; - export async function writeTemplateContents( template: PortableTemplate, input: PortableTemplateInput, 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 89b87b9a0b..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 @@ -35,9 +35,7 @@ import { targetPaths } from '@backstage/cli-common'; import { logApiReportInstructions } from '../common'; import { patchApiReportGeneration } from './patchApiReportGeneration'; -const tmpDir = targetPaths.resolveRoot( - './node_modules/.cache/api-extractor', -); +const tmpDir = targetPaths.resolveRoot('./node_modules/.cache/api-extractor'); export async function countApiReportWarnings(reportPath: string) { try { @@ -143,11 +141,7 @@ export async function runApiExtraction({ // inspected. const allDistTypesEntryPointPaths = allEntryPoints.map( ({ packageDir, distTypesPath }) => { - return targetPaths.resolveRoot( - './dist-types', - packageDir, - distTypesPath, - ); + return targetPaths.resolveRoot('./dist-types', packageDir, distTypesPath); }, ); @@ -173,10 +167,7 @@ export async function runApiExtraction({ : allowWarnings; const projectFolder = targetPaths.resolveRoot(packageDir); - const packageFolder = targetPaths.resolveRoot( - './dist-types', - 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.ts b/packages/repo-tools/src/commands/api-reports/buildApiReports.ts index 87b3f62a6c..41c6aa8a57 100644 --- a/packages/repo-tools/src/commands/api-reports/buildApiReports.ts +++ b/packages/repo-tools/src/commands/api-reports/buildApiReports.ts @@ -38,9 +38,7 @@ type Options = { } & OptionValues; export async function buildApiReports(paths: string[] = [], opts: Options) { - const tmpDir = targetPaths.resolveRoot( - './node_modules/.cache/api-extractor', - ); + const tmpDir = targetPaths.resolveRoot('./node_modules/.cache/api-extractor'); const isCiBuild = opts.ci; const isDocsBuild = opts.docs; diff --git a/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts b/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts index 7dfaa64524..973c7b8acb 100644 --- a/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts +++ b/packages/repo-tools/src/commands/api-reports/categorizePackageDirs.ts @@ -45,9 +45,7 @@ export async function categorizePackageDirs(packageDirs: string[]) { if (!role) { return; // Ignore packages without roles } - if ( - await fs.pathExists(targetPaths.resolveRoot(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/package-docs/command.ts b/packages/repo-tools/src/commands/package-docs/command.ts index 13a0603e41..3e635b34f4 100644 --- a/packages/repo-tools/src/commands/package-docs/command.ts +++ b/packages/repo-tools/src/commands/package-docs/command.ts @@ -150,10 +150,7 @@ export default async function packageDocs(paths: string[] = [], opts: any) { selectedPackageDirs.map(pkg => limit(async () => { const pkgJson = JSON.parse( - await readFile( - targetPaths.resolveRoot(pkg, 'package.json'), - 'utf-8', - ), + await readFile(targetPaths.resolveRoot(pkg, 'package.json'), 'utf-8'), ); if (EXCLUDE.includes(pkg) || pkgJson.name.startsWith('@internal/')) { return; @@ -172,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, - targetPaths.resolveRoot(`dist-types`, pkg), - ); + await cache.write(pkg, targetPaths.resolveRoot(`dist-types`, pkg)); } } catch (e) { console.error('Failed to generate docs for', pkg); diff --git a/packages/repo-tools/src/commands/package-docs/utils.ts b/packages/repo-tools/src/commands/package-docs/utils.ts index 41720f8055..97a98a28d0 100644 --- a/packages/repo-tools/src/commands/package-docs/utils.ts +++ b/packages/repo-tools/src/commands/package-docs/utils.ts @@ -18,7 +18,10 @@ import { findOwnPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; export async function createTemporaryTsConfig(dir: string) { - const path = findOwnPaths(__dirname).resolveRoot(dir, 'tsconfig.typedoc.tmp.json'); + const path = findOwnPaths(__dirname).resolveRoot( + dir, + 'tsconfig.typedoc.tmp.json', + ); process.once('exit', () => { fs.removeSync(path); diff --git a/packages/repo-tools/src/lib/paths.ts b/packages/repo-tools/src/lib/paths.ts index 3f1c5ce3f4..fea456ea3e 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -63,7 +63,9 @@ export async function resolvePackagePaths( if (include) { packages = packages.filter(pkg => include.some(pattern => - new Minimatch(pattern).match(relativePath(targetPaths.rootDir, pkg.dir)), + new Minimatch(pattern).match( + relativePath(targetPaths.rootDir, pkg.dir), + ), ), ); } From 553e727d5fe9d320fe8f61790b7adeb3336a6258 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 22 Feb 2026 14:32:02 +0100 Subject: [PATCH 39/62] Fix lint errors: add eslint-disable for __dirname, fix no-use-before-define Signed-off-by: Patrik Oldsberg --- packages/cli-common/src/paths.ts | 10 +++++----- packages/cli-node/src/paths.ts | 1 + packages/cli/src/lib/version.ts | 1 + .../modules/build/lib/bundler/moduleFederation.ts | 2 +- .../cli/src/modules/build/lib/bundler/paths.ts | 1 + packages/cli/src/modules/info/commands/info.ts | 1 + .../cli/src/modules/test/commands/package/test.ts | 1 + .../cli/src/modules/test/commands/repo/test.ts | 1 + packages/create-app/src/createApp.ts | 6 ++++-- packages/e2e-test/src/commands/runCommand.ts | 15 +++++++-------- .../repo-tools/src/commands/package-docs/utils.ts | 1 + .../src/commands/repo/schema/openapi/test.ts | 1 + packages/techdocs-cli/src/commands/serve/serve.ts | 1 + 13 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/cli-common/src/paths.ts b/packages/cli-common/src/paths.ts index f4fded7cd4..63173fb70e 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -110,11 +110,6 @@ export function findRootPath( ); } -// Finds the root of a given package -export function findOwnDir(searchDir: string) { - return OwnPathsImpl.findDir(searchDir); -} - // Finds the root of the monorepo that the package exists in. export function findOwnRootDir(ownDir: string) { const isLocal = fs.existsSync(resolvePath(ownDir, 'src')); @@ -204,6 +199,11 @@ class OwnPathsImpl implements OwnPaths { }; } +// Finds the root of a given package +export function findOwnDir(searchDir: string) { + return OwnPathsImpl.findDir(searchDir); +} + class TargetPathsImpl implements TargetPaths { #cwd: string | undefined; #dir: string | undefined; diff --git a/packages/cli-node/src/paths.ts b/packages/cli-node/src/paths.ts index 47b17c1825..334ef9eaf3 100644 --- a/packages/cli-node/src/paths.ts +++ b/packages/cli-node/src/paths.ts @@ -16,6 +16,7 @@ import { targetPaths, findOwnPaths } from '@backstage/cli-common'; +/* eslint-disable-next-line no-restricted-syntax */ const ownPaths = findOwnPaths(__dirname); /* eslint-disable-next-line no-restricted-syntax */ diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index a28feba015..aa8556534f 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -19,6 +19,7 @@ import semver from 'semver'; 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 */ 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/paths.ts b/packages/cli/src/modules/build/lib/bundler/paths.ts index 2b65052550..5a7d3b14dc 100644 --- a/packages/cli/src/modules/build/lib/bundler/paths.ts +++ b/packages/cli/src/modules/build/lib/bundler/paths.ts @@ -49,6 +49,7 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { } else { targetHtml = resolvePath(targetDir, `${entry}.html`); if (!fs.pathExistsSync(targetHtml)) { + /* eslint-disable-next-line no-restricted-syntax */ targetHtml = findOwnPaths(__dirname).resolve( 'templates/serve_index.html', ); diff --git a/packages/cli/src/modules/info/commands/info.ts b/packages/cli/src/modules/info/commands/info.ts index 6fcf78cc84..c50a9da373 100644 --- a/packages/cli/src/modules/info/commands/info.ts +++ b/packages/cli/src/modules/info/commands/info.ts @@ -55,6 +55,7 @@ function hasBackstageField(packageName: string, targetPath: string): boolean { export default async (options: InfoOptions) => { await new Promise(async () => { const yarnVersion = await runOutput(['yarn', '--version']); + /* eslint-disable-next-line no-restricted-syntax */ const isLocal = fs.existsSync(findOwnPaths(__dirname).resolve('./src')); const backstageFile = targetPaths.resolveRoot('backstage.json'); diff --git a/packages/cli/src/modules/test/commands/package/test.ts b/packages/cli/src/modules/test/commands/package/test.ts index 6553ad93c9..c4acfb287b 100644 --- a/packages/cli/src/modules/test/commands/package/test.ts +++ b/packages/cli/src/modules/test/commands/package/test.ts @@ -38,6 +38,7 @@ export default async (_opts: OptionValues, cmd: Command) => { // Only include our config if caller isn't passing their own config if (!includesAnyOf(args, '-c', '--config')) { + /* eslint-disable-next-line no-restricted-syntax */ args.push('--config', findOwnPaths(__dirname).resolve('config/jest.js')); } diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index 46af4e6e4d..1f57279935 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -167,6 +167,7 @@ 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')) { + /* eslint-disable-next-line no-restricted-syntax */ args.push('--config', findOwnPaths(__dirname).resolve('config/jest.js')); } diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index 9b09f59904..64db2e52ab 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -64,9 +64,11 @@ 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 - ? findOwnPaths(__dirname).resolve('templates/next-app') - : findOwnPaths(__dirname).resolve('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 diff --git a/packages/e2e-test/src/commands/runCommand.ts b/packages/e2e-test/src/commands/runCommand.ts index ca95a2fa3e..dd9dd9b397 100644 --- a/packages/e2e-test/src/commands/runCommand.ts +++ b/packages/e2e-test/src/commands/runCommand.ts @@ -28,6 +28,9 @@ import mysql from 'mysql2/promise'; import pgtools from 'pgtools'; import { findOwnPaths, runOutput, run } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const ownPaths = findOwnPaths(__dirname); import { OptionValues } from 'commander'; const templatePackagePaths = [ @@ -135,7 +138,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { } for (const pkgJsonPath of templatePackagePaths) { - const jsonPath = findOwnPaths(__dirname).resolveRoot(pkgJsonPath); + const jsonPath = ownPaths.resolveRoot(pkgJsonPath); const pkgTemplate = await fs.readFile(jsonPath, 'utf8'); const pkg = JSON.parse( handlebars.compile(pkgTemplate)( @@ -193,7 +196,7 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { print('Pinning yarn version in workspace'); await pinYarnVersion(workspaceDir); - const yarnPatchesPath = findOwnPaths(__dirname).resolveRoot('.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')); @@ -211,10 +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( - findOwnPaths(__dirname).resolveRoot('.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,7 +225,6 @@ async function pinYarnVersion(dir: string) { throw new Error(`Invalid 'yarnPath' in ${yarnRc}`); } const [, localYarnPath] = match; - const ownPaths = findOwnPaths(__dirname); const yarnPath = ownPaths.resolveRoot(localYarnPath); const yarnPluginPath = ownPaths.resolveRoot( localYarnPath, @@ -329,7 +328,7 @@ async function createApp( */ async function overrideYarnLockSeed(appDir: string) { const content = await fs.readFile( - findOwnPaths(__dirname).resolveRoot('packages/create-app/seed-yarn.lock'), + ownPaths.resolveRoot('packages/create-app/seed-yarn.lock'), 'utf8', ); const trimmedContent = content diff --git a/packages/repo-tools/src/commands/package-docs/utils.ts b/packages/repo-tools/src/commands/package-docs/utils.ts index 97a98a28d0..21294daa79 100644 --- a/packages/repo-tools/src/commands/package-docs/utils.ts +++ b/packages/repo-tools/src/commands/package-docs/utils.ts @@ -18,6 +18,7 @@ import { findOwnPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; export async function createTemporaryTsConfig(dir: string) { + /* eslint-disable-next-line no-restricted-syntax */ const path = findOwnPaths(__dirname).resolveRoot( dir, 'tsconfig.typedoc.tmp.json', 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 123a1182ea..d583854059 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/test.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/test.ts @@ -43,6 +43,7 @@ async function test( try { opticLocation = ( await exec(`yarn bin optic`, [], { + /* eslint-disable-next-line no-restricted-syntax */ cwd: findOwnPaths(__dirname).rootDir, }) ).stdout as string; diff --git a/packages/techdocs-cli/src/commands/serve/serve.ts b/packages/techdocs-cli/src/commands/serve/serve.ts index 511cad0472..10b7e1498f 100644 --- a/packages/techdocs-cli/src/commands/serve/serve.ts +++ b/packages/techdocs-cli/src/commands/serve/serve.ts @@ -39,6 +39,7 @@ 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 findOwnPaths(__dirname).resolve('dist/embedded-app'); } } From ebc01ef04d378b56895b6181b90936ddc23241bd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 14:20:59 +0100 Subject: [PATCH 40/62] Add overrideTargetPaths test utility and fix rebase issues Adds `overrideTargetPaths` to `@backstage/cli-common/testUtils` for cleanly mocking `targetPaths` in tests without `jest.mock` or `jest.spyOn`. Migrates all existing test mocks to use the new utility. Also fixes translations module imports broken by the rebase. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../src/manager/plugin-manager.test.ts | 11 +-- packages/backend/package.json | 2 +- packages/cli-common/package.json | 19 ++++- packages/cli-common/report-testUtils.api.md | 23 ++++++ packages/cli-common/report.api.md | 1 - packages/cli-common/src/errors.ts | 1 + packages/cli-common/src/paths.ts | 20 +++++ packages/cli-common/src/testUtils.ts | 78 +++++++++++++++++++ packages/cli/src/lib/yarnPlugin.test.ts | 10 +-- .../modules/build/commands/repo/start.test.ts | 10 +-- .../cli/src/modules/build/lib/role.test.ts | 16 +--- .../migrate/commands/versions/bump.test.ts | 15 ++-- .../migrate/commands/versions/migrate.test.ts | 12 +-- .../execution/writeTemplateContents.test.ts | 24 ++++-- .../modules/translations/commands/export.ts | 12 +-- .../modules/translations/commands/import.ts | 8 +- packages/create-app/src/createApp.test.ts | 18 ++--- .../api-reports/buildApiReports.test.ts | 51 ++++++------ 18 files changed, 210 insertions(+), 121 deletions(-) create mode 100644 packages/cli-common/report-testUtils.api.md create mode 100644 packages/cli-common/src/testUtils.ts 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 b778e4df6e..a9340d5962 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 @@ -39,6 +39,7 @@ import { ConfigSources } from '@backstage/config-loader'; import { Logs, MockedLogger, LogContent } from '../__testUtils__/testUtils'; import { PluginScanner } from '../scanner/plugin-scanner'; import { targetPaths } from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; @@ -47,15 +48,7 @@ describe('backend-dynamic-feature-service', () => { const mockDir = createMockDirectory(); beforeAll(() => { - jest - .spyOn(targetPaths, 'resolveRoot') - .mockImplementation((...paths: string[]) => - require('path').resolve(__dirname, '../../../..', ...paths), - ); - }); - - afterAll(() => { - jest.restoreAllMocks(); + overrideTargetPaths(require('path').resolve(__dirname, '../../../..')); }); describe('loadPlugins', () => { diff --git a/packages/backend/package.json b/packages/backend/package.json index fee2734e6e..b6b97f214e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -61,6 +61,7 @@ "@backstage/plugin-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", "@backstage/plugin-search-backend-module-elasticsearch": "workspace:^", + "@backstage/plugin-search-backend-module-explore": "workspace:^", "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-signals-backend": "workspace:^", @@ -68,7 +69,6 @@ "@opentelemetry/auto-instrumentations-node": "^0.67.0", "@opentelemetry/exporter-prometheus": "^0.211.0", "@opentelemetry/sdk-node": "^0.211.0", - "@backstage/plugin-search-backend-module-explore": "workspace:^", "example-app": "link:../app" }, "devDependencies": { diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 9134eeeaee..4eae1d96a4 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -6,9 +6,7 @@ "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 18f2ccb63c..ba649cacc9 100644 --- a/packages/cli-common/report.api.md +++ b/packages/cli-common/report.api.md @@ -16,7 +16,6 @@ export function bootstrapEnvProxyAgents(): void; // @public export class ExitCodeError extends CustomErrorBase { constructor(code: number, command?: string); - // (undocumented) readonly code: number; } 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/paths.ts b/packages/cli-common/src/paths.ts index 63173fb70e..1cd84d4f5b 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -204,12 +204,23 @@ 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; @@ -224,6 +235,9 @@ class TargetPathsImpl implements TargetPaths { } 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) { @@ -246,10 +260,16 @@ class TargetPathsImpl implements TargetPaths { } 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); }; } 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/src/lib/yarnPlugin.test.ts b/packages/cli/src/lib/yarnPlugin.test.ts index a51fa4864a..a07c2a2ac6 100644 --- a/packages/cli/src/lib/yarnPlugin.test.ts +++ b/packages/cli/src/lib/yarnPlugin.test.ts @@ -15,21 +15,15 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; -import { targetPaths } from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { getHasYarnPlugin } from './yarnPlugin'; const mockDir = createMockDirectory(); +overrideTargetPaths(mockDir.path); describe('getHasYarnPlugin', () => { beforeEach(() => { mockDir.clear(); - jest - .spyOn(targetPaths, 'resolveRoot') - .mockImplementation((...args: string[]) => mockDir.resolve(...args)); - }); - - afterEach(() => { - jest.restoreAllMocks(); }); it('should return false when .yarnrc.yml does not exist', async () => { 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 54414b7e90..a9eb01b21b 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 { targetPaths } from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; + +overrideTargetPaths({ dir: '/root', rootDir: '/root' }); const mocks = { app: { @@ -97,11 +98,6 @@ const mocks = { describe('findTargetPackages', () => { beforeEach(() => { jest.clearAllMocks(); - jest - .spyOn(targetPaths, 'resolveRoot') - .mockImplementation((...parts: string[]) => { - return posix.resolve('/root', ...parts); - }); }); it('should select default packages', async () => { diff --git a/packages/cli/src/modules/build/lib/role.test.ts b/packages/cli/src/modules/build/lib/role.test.ts index 76b202ae98..dbed4310fa 100644 --- a/packages/cli/src/modules/build/lib/role.test.ts +++ b/packages/cli/src/modules/build/lib/role.test.ts @@ -15,24 +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('@backstage/cli-common', () => ({ - ...jest.requireActual('@backstage/cli-common'), - targetPaths: { - get dir() { - return mockDir.path; - }, - get rootDir() { - return mockDir.path; - }, - resolve: (...args: string[]) => mockDir.resolve(...args), - resolveRoot: (...args: string[]) => mockDir.resolve(...args), - }, -})); +overrideTargetPaths(mockDir.path); describe('findRoleFromCommand', () => { function mkCommand(args?: string) { 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 eafe141e57..b44de6fc6b 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -16,6 +16,7 @@ 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'; @@ -64,16 +65,6 @@ jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - targetPaths: { - get dir() { - return mockDir.path; - }, - get rootDir() { - return mockDir.path; - }, - resolve: (...args: string[]) => mockDir.resolve(...args), - resolveRoot: (...args: string[]) => mockDir.resolve(...args), - }, findPaths: () => ({ resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), get targetDir() { @@ -147,6 +138,7 @@ const expectLogsToMatch = ( describe('bump', () => { mockDir = createMockDirectory(); + beforeAll(() => overrideTargetPaths(mockDir.path)); beforeEach(() => { mockFetchPackageInfo.mockImplementation(async name => ({ @@ -953,6 +945,7 @@ describe('bump', () => { describe('bumpBackstageJsonVersion', () => { mockDir = createMockDirectory(); + beforeAll(() => overrideTargetPaths(mockDir.path)); afterEach(() => { jest.resetAllMocks(); @@ -1089,6 +1082,8 @@ describe('environment variables', () => { const worker = setupServer(); registerMswTestHooks(worker); + beforeAll(() => 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/migrate.test.ts b/packages/cli/src/modules/migrate/commands/versions/migrate.test.ts index 74ba9ae975..16684d36f3 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'; @@ -37,16 +38,6 @@ jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - targetPaths: { - get dir() { - return mockDir.path; - }, - get rootDir() { - return mockDir.path; - }, - resolve: (...args: string[]) => mockDir.resolve(...args), - resolveRoot: (...args: string[]) => mockDir.resolve(...args), - }, findPaths: () => ({ resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), get targetDir() { @@ -66,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/execution/writeTemplateContents.test.ts b/packages/cli/src/modules/new/lib/execution/writeTemplateContents.test.ts index 768f46e20e..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 { targetPaths } from '@backstage/cli-common'; +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(targetPaths, 'resolveRoot') - .mockImplementation((...args: string[]) => 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/translations/commands/export.ts b/packages/cli/src/modules/translations/commands/export.ts index 96b3ceb0c6..0329b1241a 100644 --- a/packages/cli/src/modules/translations/commands/export.ts +++ b/packages/cli/src/modules/translations/commands/export.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; import { dirname, resolve as resolvePath } from 'node:path'; import { @@ -41,14 +41,14 @@ export default async (options: ExportOptions) => { validatePattern(options.pattern); const targetPackageJson = await readTargetPackage( - paths.targetDir, - paths.targetRoot, + targetPaths.dir, + targetPaths.rootDir, ); - const outputDir = resolvePath(paths.targetDir, options.output); + const outputDir = resolvePath(targetPaths.dir, options.output); const manifestPath = resolvePath(outputDir, 'manifest.json'); - const tsconfigPath = paths.resolveTargetRoot('tsconfig.json'); + const tsconfigPath = targetPaths.resolveRoot('tsconfig.json'); if (!(await fs.pathExists(tsconfigPath))) { throw new Error( `No tsconfig.json found at ${tsconfigPath}. ` + @@ -61,7 +61,7 @@ export default async (options: ExportOptions) => { ); const packages = await discoverFrontendPackages( targetPackageJson, - paths.targetDir, + targetPaths.dir, ); console.log(`Found ${packages.length} frontend packages to scan`); diff --git a/packages/cli/src/modules/translations/commands/import.ts b/packages/cli/src/modules/translations/commands/import.ts index 7275da4c24..c104275f46 100644 --- a/packages/cli/src/modules/translations/commands/import.ts +++ b/packages/cli/src/modules/translations/commands/import.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths } from '../../../lib/paths'; +import { targetPaths } from '@backstage/cli-common'; import fs from 'fs-extra'; import { resolve as resolvePath, @@ -45,11 +45,11 @@ interface Manifest { } export default async (options: ImportOptions) => { - await readTargetPackage(paths.targetDir, paths.targetRoot); + await readTargetPackage(targetPaths.dir, targetPaths.rootDir); - const inputDir = resolvePath(paths.targetDir, options.input); + const inputDir = resolvePath(targetPaths.dir, options.input); const manifestPath = resolvePath(inputDir, 'manifest.json'); - const outputPath = resolvePath(paths.targetDir, options.output); + const outputPath = resolvePath(targetPaths.dir, options.output); if (!(await fs.pathExists(manifestPath))) { throw new Error( diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index 56dded39ee..1f78c084c5 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -22,14 +22,18 @@ import createApp from './createApp'; 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 }); + jest.mock('@backstage/cli-common', () => { const pathModule = require('node:path'); const actual = jest.requireActual('@backstage/cli-common'); const MOCK_CREATE_APP_ROOT = '/mock/create-app-root'; - const MOCK_TARGET_DIR = '/mock/target-dir'; const mockOwnPaths = { resolve: (...paths: string[]) => pathModule.join(MOCK_CREATE_APP_ROOT, ...paths), @@ -40,18 +44,6 @@ jest.mock('@backstage/cli-common', () => { ...actual, findPaths: jest.fn(), findOwnPaths: () => mockOwnPaths, - targetPaths: { - get dir() { - return MOCK_TARGET_DIR; - }, - get rootDir() { - return '/mock/target-root'; - }, - resolve: (...paths: string[]) => - pathModule.resolve(MOCK_TARGET_DIR, ...paths), - resolveRoot: (...paths: string[]) => - pathModule.resolve('/mock/target-root', ...paths), - }, }; }); 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 000ef11cac..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 { targetPaths } from '@backstage/cli-common'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { categorizePackageDirs } from './categorizePackageDirs'; @@ -52,11 +52,8 @@ jest.mock('./categorizePackageDirs', () => ({ })); const mockDir = createMockDirectory(); +overrideTargetPaths(mockDir.path); -jest.spyOn(targetPaths, 'rootDir', 'get').mockReturnValue(mockDir.path); -jest - .spyOn(targetPaths, 'resolveRoot') - .mockImplementation((...path: string[]) => mockDir.resolve(...path)); jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ { dir: normalize(mockDir.resolve('packages/package-a')), @@ -83,30 +80,28 @@ jest.spyOn(PackageGraph, 'listTargetPackages').mockResolvedValue([ describe('buildApiReports', () => { beforeEach(() => { mockDir.setContent({ - [targetPaths.rootDir]: { - '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': '{}', }, }, }); From f2f6e3d47a31383e44daf7bd28112325411cffa9 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Mon, 23 Feb 2026 15:15:45 +0100 Subject: [PATCH 41/62] refactor(ui): centralize prop resolution in useDefinition Extract prop-splitting and responsive resolution with default fallbacks from `useDefinition` into a new `resolveDefinitionProps` helper. This makes `propDefs.default` the single authoritative source of truth for default values. Previously, `useBgProvider` had a separate manual default lookup (`props.bg ?? (definition.propDefs as any).bg?.default`) that duplicated the main resolution loop. Signed-off-by: Johan Persson --- .../ui/src/hooks/useDefinition/helpers.ts | 38 +++++++++++++++- .../src/hooks/useDefinition/useDefinition.tsx | 44 +++++++------------ 2 files changed, 52 insertions(+), 30 deletions(-) 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/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); From 0f462f85fe39cfb6c052b63ba7996f12f92ab03c Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Mon, 23 Feb 2026 17:06:32 +0100 Subject: [PATCH 42/62] refactor(ui): enforce required children on bg provider component types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strengthens BgPropsConstraint to also check that children is present and non-optional in the OwnProps type of bg provider components. This ensures children can only flow through childrenWithBgProvider, preventing silent bypasses of the bg context system. Box and Accordion OwnProps updated to comply — children is now required. BoxProps updated to Omit children from React.HTMLAttributes to avoid an incompatible duplicate property declaration. Storybook stories updated accordingly. Signed-off-by: Johan Persson --- .changeset/rude-groups-shout.md | 5 +++++ packages/ui/report.api.md | 6 +++--- packages/ui/src/components/Accordion/types.ts | 2 +- packages/ui/src/components/Box/Box.stories.tsx | 6 ++++-- packages/ui/src/components/Box/types.ts | 4 ++-- .../src/components/Container/Container.stories.tsx | 1 + packages/ui/src/components/Flex/Flex.stories.tsx | 1 + packages/ui/src/components/Grid/Grid.stories.tsx | 2 ++ packages/ui/src/hooks/useDefinition/types.ts | 14 +++++++++++--- 9 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 .changeset/rude-groups-shout.md 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/packages/ui/report.api.md b/packages/ui/report.api.md index 87cea3d387..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; }; @@ -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 = { 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/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.'; } : {}; From ee877203009193fde6b19246137a67d13be861aa Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 17:21:40 +0100 Subject: [PATCH 43/62] scaffolder: add back form fields API alpha exports Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/scaffolder-export-form-fields-api.md | 5 +++++ .patches/pr-32969.txt | 1 + plugins/scaffolder/report-alpha.api.md | 9 +++++++++ plugins/scaffolder/src/alpha/formFieldsApi.ts | 13 +++++++------ plugins/scaffolder/src/alpha/index.ts | 4 ++++ 5 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 .changeset/scaffolder-export-form-fields-api.md create mode 100644 .patches/pr-32969.txt 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/.patches/pr-32969.txt b/.patches/pr-32969.txt new file mode 100644 index 0000000000..15dc342a21 --- /dev/null +++ b/.patches/pr-32969.txt @@ -0,0 +1 @@ +Add back `formFieldsApiRef` and `ScaffolderFormFieldsApi` alpha exports from `@backstage/plugin-scaffolder` 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'; From 641d88cb07562beb2c3d4ca0ae1e619a7a321a98 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 21:01:27 +0100 Subject: [PATCH 44/62] Address PR review comments - Remove cli-node/src/paths.ts compat layer, migrate all cli-node internal usage to import targetPaths from @backstage/cli-common - Use single-arg overrideTargetPaths('/root') where dir === rootDir - Scope mockDir to each describe block in bump.test.ts to avoid shared state issues with overrideTargetPaths - Remove unnecessary overrideTargetPaths from plugin-manager.test.ts - Remove stale findPaths mock from createApp.test.ts - Use overrideTargetPaths in getWorkspaceRoot.test.ts and cli-node tests Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .../src/manager/plugin-manager.test.ts | 5 --- packages/cli-node/src/git/GitUtils.ts | 6 +-- .../src/monorepo/PackageGraph.test.ts | 9 +---- .../cli-node/src/monorepo/PackageGraph.ts | 8 ++-- packages/cli-node/src/monorepo/isMonoRepo.ts | 4 +- .../cli-node/src/monorepo/isMonorepo.test.ts | 6 +-- .../src/pacman/PackageManager.test.ts | 7 +--- .../cli-node/src/pacman/PackageManager.ts | 6 +-- .../cli-node/src/pacman/yarn/Yarn.test.ts | 7 +--- packages/cli-node/src/pacman/yarn/Yarn.ts | 4 +- packages/cli-node/src/paths.ts | 40 ------------------- .../modules/build/commands/repo/start.test.ts | 2 +- .../migrate/commands/versions/bump.test.ts | 29 ++++++-------- packages/create-app/src/createApp.test.ts | 1 - .../src/util/getWorkspaceRoot.test.ts | 24 ++--------- 15 files changed, 40 insertions(+), 118 deletions(-) delete mode 100644 packages/cli-node/src/paths.ts 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 a9340d5962..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 @@ -39,7 +39,6 @@ import { ConfigSources } from '@backstage/config-loader'; import { Logs, MockedLogger, LogContent } from '../__testUtils__/testUtils'; import { PluginScanner } from '../scanner/plugin-scanner'; import { targetPaths } from '@backstage/cli-common'; -import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle'; import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; @@ -47,10 +46,6 @@ import { BackstagePackageJson, PackageRole } from '@backstage/cli-node'; describe('backend-dynamic-feature-service', () => { const mockDir = createMockDirectory(); - beforeAll(() => { - overrideTargetPaths(require('path').resolve(__dirname, '../../../..')); - }); - describe('loadPlugins', () => { afterEach(() => { jest.resetModules(); 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/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 da78c8dd53..93a5e48abb 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'; /** @@ -23,7 +23,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?.packages); 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 dd35e74902..ef169b1337 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 44c0849705..b908e99c72 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'; @@ -91,7 +91,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(); @@ -99,7 +99,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-node/src/pacman/yarn/Yarn.test.ts b/packages/cli-node/src/pacman/yarn/Yarn.test.ts index 9bf866b821..42b5caa6c5 100644 --- a/packages/cli-node/src/pacman/yarn/Yarn.test.ts +++ b/packages/cli-node/src/pacman/yarn/Yarn.test.ts @@ -15,14 +15,11 @@ */ import { createMockDirectory } from '@backstage/backend-test-utils'; +import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; import { Yarn } from './Yarn'; const mockDir = createMockDirectory(); - -jest.mock('../../paths', () => ({ - ...jest.requireActual('../../paths'), - paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, -})); +overrideTargetPaths(mockDir.path); const yarnClassic = new Yarn({ version: '1.0.0', codename: 'classic' }); const yarnBerry = new Yarn({ version: '3.0.0', codename: 'berry' }); diff --git a/packages/cli-node/src/pacman/yarn/Yarn.ts b/packages/cli-node/src/pacman/yarn/Yarn.ts index a6544344ca..b153a6ef40 100644 --- a/packages/cli-node/src/pacman/yarn/Yarn.ts +++ b/packages/cli-node/src/pacman/yarn/Yarn.ts @@ -23,7 +23,7 @@ import { PackageInfo, PackageManager } from '../PackageManager'; import { Lockfile } from '../Lockfile'; import { YarnVersion } from './types'; import fs from 'fs-extra'; -import { paths } from '../../paths'; +import { targetPaths } from '@backstage/cli-common'; import { run, runOutput, RunOptions } from '@backstage/cli-common'; export class Yarn implements PackageManager { @@ -47,7 +47,7 @@ export class Yarn implements PackageManager { } async getMonorepoPackages() { - const rootPackageJsonPath = paths.resolveTargetRoot('package.json'); + const rootPackageJsonPath = targetPaths.resolveRoot('package.json'); try { const pkg = await fs.readJson(rootPackageJsonPath); return pkg?.workspaces?.packages || []; diff --git a/packages/cli-node/src/paths.ts b/packages/cli-node/src/paths.ts deleted file mode 100644 index 334ef9eaf3..0000000000 --- a/packages/cli-node/src/paths.ts +++ /dev/null @@ -1,40 +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 { targetPaths, findOwnPaths } from '@backstage/cli-common'; - -/* eslint-disable-next-line no-restricted-syntax */ -const ownPaths = findOwnPaths(__dirname); - -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = { - get ownDir() { - return ownPaths.dir; - }, - get ownRoot() { - return ownPaths.rootDir; - }, - get targetDir() { - return targetPaths.dir; - }, - get targetRoot() { - return targetPaths.rootDir; - }, - resolveOwn: ownPaths.resolve, - resolveOwnRoot: ownPaths.resolveRoot, - resolveTarget: targetPaths.resolve, - resolveTargetRoot: targetPaths.resolveRoot, -}; 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 a9eb01b21b..328c8fd365 100644 --- a/packages/cli/src/modules/build/commands/repo/start.test.ts +++ b/packages/cli/src/modules/build/commands/repo/start.test.ts @@ -18,7 +18,7 @@ import { PackageGraph } from '@backstage/cli-node'; import { findTargetPackages } from './start'; import { overrideTargetPaths } from '@backstage/cli-common/testUtils'; -overrideTargetPaths({ dir: '/root', rootDir: '/root' }); +overrideTargetPaths('/root'); const mocks = { app: { 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 b44de6fc6b..cc662f9d5e 100644 --- a/packages/cli/src/modules/migrate/commands/versions/bump.test.ts +++ b/packages/cli/src/modules/migrate/commands/versions/bump.test.ts @@ -23,10 +23,7 @@ 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', () => ({ @@ -60,17 +57,10 @@ jest.mock('ora', () => ({ }, })); -let mockDir: MockDirectory; jest.mock('@backstage/cli-common', () => { const actual = jest.requireActual('@backstage/cli-common'); return { ...actual, - findPaths: () => ({ - resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args), - get targetDir() { - return mockDir.path; - }, - }), run: jest.fn().mockReturnValue({ exitCode: null, waitForExit: jest.fn().mockResolvedValue(undefined), @@ -137,10 +127,10 @@ const expectLogsToMatch = ( }; describe('bump', () => { - mockDir = createMockDirectory(); - beforeAll(() => overrideTargetPaths(mockDir.path)); + const mockDir = createMockDirectory(); beforeEach(() => { + overrideTargetPaths(mockDir.path); mockFetchPackageInfo.mockImplementation(async name => ({ name: name, 'dist-tags': { @@ -944,8 +934,11 @@ describe('bump', () => { }); describe('bumpBackstageJsonVersion', () => { - mockDir = createMockDirectory(); - beforeAll(() => overrideTargetPaths(mockDir.path)); + const mockDir = createMockDirectory(); + + beforeEach(() => { + overrideTargetPaths(mockDir.path); + }); afterEach(() => { jest.resetAllMocks(); @@ -1079,10 +1072,14 @@ describe('createVersionFinder', () => { }); describe('environment variables', () => { + const mockDir = createMockDirectory(); + const worker = setupServer(); registerMswTestHooks(worker); - beforeAll(() => overrideTargetPaths(mockDir.path)); + beforeEach(() => { + overrideTargetPaths(mockDir.path); + }); beforeEach(() => { delete process.env.BACKSTAGE_MANIFEST_FILE; diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index 1f78c084c5..d49078887c 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -42,7 +42,6 @@ jest.mock('@backstage/cli-common', () => { }; return { ...actual, - findPaths: jest.fn(), findOwnPaths: () => mockOwnPaths, }; }); diff --git a/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts b/packages/yarn-plugin/src/util/getWorkspaceRoot.test.ts index 0f44429707..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 { targetPaths } 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 mockResolveRoot: jest.MockedFunction; beforeEach(() => { realPlatform = process.platform; @@ -45,21 +42,10 @@ describe('getWorkspaceRoot', () => { jest.resetModules(); - mockResolveRoot = jest.fn(); - - jest.doMock('@backstage/cli-common', () => ({ - ...jest.requireActual('@backstage/cli-common'), - targetPaths: { - get dir() { - return mockResolveRoot(); - }, - get rootDir() { - return mockResolveRoot(); - }, - resolveRoot: mockResolveRoot, - }, - })); - + const { + overrideTargetPaths, + } = require('@backstage/cli-common/testUtils'); + overrideTargetPaths(native); getWorkspaceRoot = require('./getWorkspaceRoot').getWorkspaceRoot; }); @@ -68,8 +54,6 @@ describe('getWorkspaceRoot', () => { }); it('returns an appropriately-formatted workspace root path', () => { - mockResolveRoot.mockReturnValue(native); - expect(getWorkspaceRoot()).toEqual(portable); }); }); From 8c3802c5baf3f61138ad4d06bdf2880379b7b47e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 21:15:48 +0100 Subject: [PATCH 45/62] Add @backstage/cli to changeset, remove cli-common mock from create-app test Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/migrate-to-target-paths.md | 1 + packages/create-app/src/createApp.test.ts | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.changeset/migrate-to-target-paths.md b/.changeset/migrate-to-target-paths.md index a3c0c0c57e..efc03ba289 100644 --- a/.changeset/migrate-to-target-paths.md +++ b/.changeset/migrate-to-target-paths.md @@ -1,4 +1,5 @@ --- +'@backstage/cli': patch '@backstage/cli-node': patch '@backstage/backend-dynamic-feature-service': patch '@backstage/codemods': patch diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index d49078887c..c38186b1d8 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -30,22 +30,6 @@ const MOCK_TARGET_DIR = '/mock/target-dir'; const MOCK_TARGET_ROOT = '/mock/target-root'; overrideTargetPaths({ dir: MOCK_TARGET_DIR, rootDir: MOCK_TARGET_ROOT }); -jest.mock('@backstage/cli-common', () => { - const pathModule = require('node:path'); - const actual = jest.requireActual('@backstage/cli-common'); - const MOCK_CREATE_APP_ROOT = '/mock/create-app-root'; - const mockOwnPaths = { - resolve: (...paths: string[]) => - pathModule.join(MOCK_CREATE_APP_ROOT, ...paths), - resolveRoot: (...paths: string[]) => - pathModule.join('/mock/monorepo-root', ...paths), - }; - return { - ...actual, - findOwnPaths: () => mockOwnPaths, - }; -}); - // 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' }, From 909c742c183a7514df8a51ee843a8e6fe3978b2e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 16 Feb 2026 11:36:59 +0100 Subject: [PATCH 46/62] Stabilize translation API in the new frontend system Remove @alpha tags from translation-related types and switch all translation API imports in new frontend system packages to use stable paths from @backstage/frontend-plugin-api instead of @backstage/core-plugin-api/alpha. Signed-off-by: Patrik Oldsberg --- .changeset/stable-translation-plugin-app.md | 5 +++++ .changeset/stable-translation-test-utils.md | 5 +++++ .../src/apis/definitions/TranslationApi.ts | 2 +- packages/frontend-test-utils/report.api.md | 13 ++++++------- .../apis/TranslationApi/MockTranslationApi.test.tsx | 2 +- .../src/apis/TranslationApi/MockTranslationApi.ts | 4 ++-- packages/frontend-test-utils/src/apis/mockApis.ts | 6 +++--- plugins/app/src/extensions/AppLanguageApi.ts | 2 +- plugins/app/src/extensions/TranslationsApi.tsx | 2 +- 9 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 .changeset/stable-translation-plugin-app.md create mode 100644 .changeset/stable-translation-test-utils.md 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/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/report.api.md b/packages/frontend-test-utils/report.api.md index d1181f032d..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,11 +264,11 @@ export namespace mockApis { ) => ApiMock; } export function translation(): MockTranslationApi & - MockWithApiFactory; + MockWithApiFactory; export namespace translation { const mock: ( - partialImpl?: Partial | undefined, - ) => ApiMock; + partialImpl?: Partial | undefined, + ) => ApiMock; } } 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/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'; From 2a515460e864562d7421cf773f0f8e48ef8575c4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 23 Feb 2026 21:43:50 +0100 Subject: [PATCH 47/62] Fix prettier existence checks and import order Use fs.pathExists instead of checking resolved path strings which are always truthy. Fix import ordering in e2e-test runCommand.ts. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .changeset/fix-prettier-existence-check.md | 5 +++++ packages/e2e-test/src/commands/runCommand.ts | 2 +- .../src/commands/package/schema/openapi/generate/client.ts | 4 ++-- .../src/commands/package/schema/openapi/generate/server.ts | 4 +++- .../repo-tools/src/commands/package/schema/openapi/init.ts | 6 ++++-- .../repo-tools/src/commands/repo/schema/openapi/test.ts | 4 +++- 6 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 .changeset/fix-prettier-existence-check.md 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/packages/e2e-test/src/commands/runCommand.ts b/packages/e2e-test/src/commands/runCommand.ts index dd9dd9b397..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 { OptionValues } from 'commander'; import { findOwnPaths, runOutput, run } from '@backstage/cli-common'; /* eslint-disable-next-line no-restricted-syntax */ const ownPaths = findOwnPaths(__dirname); -import { OptionValues } from 'commander'; const templatePackagePaths = [ 'packages/cli/templates/frontend-plugin/package.json.hbs', 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 17033d881a..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 @@ -87,7 +87,7 @@ async function generate( await fs.writeFile( resolve(parentDirectory, 'index.ts'), - `// + `// export * from './generated';`, ); @@ -96,7 +96,7 @@ async function generate( }); const prettier = targetPaths.resolveRoot('node_modules/.bin/prettier'); - if (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 88c6df781a..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 @@ -77,7 +77,9 @@ export const createOpenApiRouter = async ( ); await exec(`yarn backstage-cli package lint`, ['--fix', tsPath, indexFile]); - if (await targetPaths.resolveRoot('node_modules/.bin/prettier')) { + if ( + await fs.pathExists(targetPaths.resolveRoot('node_modules/.bin/prettier')) + ) { await exec(`yarn prettier`, ['--write', tsPath, indexFile], { cwd: targetPaths.rootDir, }); 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 558a9a7387..04b6e73483 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/init.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/init.ts @@ -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 targetPaths.resolveRoot('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/test.ts b/packages/repo-tools/src/commands/repo/schema/openapi/test.ts index d583854059..e735e729c6 100644 --- a/packages/repo-tools/src/commands/repo/schema/openapi/test.ts +++ b/packages/repo-tools/src/commands/repo/schema/openapi/test.ts @@ -82,7 +82,9 @@ async function test( throw err; } if ( - (await targetPaths.resolveRoot('node_modules/.bin/prettier')) && + (await fs.pathExists( + targetPaths.resolveRoot('node_modules/.bin/prettier'), + )) && options?.update ) { await exec(`yarn prettier`, ['--write', openapiPath]); From 5cefb88bb2e4cb940b9c1868baafd01f7c253a89 Mon Sep 17 00:00:00 2001 From: John Philip Date: Mon, 23 Feb 2026 16:30:33 -0500 Subject: [PATCH 48/62] perform search on first navigate Signed-off-by: John Philip --- plugins/search-react/src/context/SearchContext.tsx | 3 +-- plugins/search/src/components/SearchPage/SearchPage.tsx | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) 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/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(() => { From 48235027e44f61374da72365a7c06f6cc570d8e3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 00:32:29 +0100 Subject: [PATCH 49/62] chore: remove applied patch files Signed-off-by: Patrik Oldsberg --- .patches/pr-32903.txt | 1 - .patches/pr-32905.txt | 1 - .patches/pr-32950.txt | 1 - .patches/pr-32969.txt | 1 - 4 files changed, 4 deletions(-) delete mode 100644 .patches/pr-32903.txt delete mode 100644 .patches/pr-32905.txt delete mode 100644 .patches/pr-32950.txt delete mode 100644 .patches/pr-32969.txt 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-32950.txt b/.patches/pr-32950.txt deleted file mode 100644 index 4d68055cce..0000000000 --- a/.patches/pr-32950.txt +++ /dev/null @@ -1 +0,0 @@ -Updated `@microsoft/api-extractor` to `7.57.3` \ No newline at end of file diff --git a/.patches/pr-32969.txt b/.patches/pr-32969.txt deleted file mode 100644 index 15dc342a21..0000000000 --- a/.patches/pr-32969.txt +++ /dev/null @@ -1 +0,0 @@ -Add back `formFieldsApiRef` and `ScaffolderFormFieldsApi` alpha exports from `@backstage/plugin-scaffolder` From d5eb954544bbb95fb58cf500fc894694ec277a6f Mon Sep 17 00:00:00 2001 From: John Philip Date: Tue, 24 Feb 2026 03:20:29 -0500 Subject: [PATCH 50/62] changeset Signed-off-by: John Philip --- .changeset/bright-moons-open.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/bright-moons-open.md 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. From 1e8fdd338cfafb5f9667f65d1c389b219b96bdfe Mon Sep 17 00:00:00 2001 From: John Philip Date: Tue, 24 Feb 2026 03:25:07 -0500 Subject: [PATCH 51/62] add patch Signed-off-by: John Philip --- .patches/pr-32973.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 .patches/pr-32973.txt 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 From 1ee5b28e41c274ea38c16a07290387763b5e2284 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Tue, 24 Feb 2026 16:57:02 +0100 Subject: [PATCH 52/62] `feat(metrics)`: Implement `MetricsService` (#32977) * feat: add MetricsService alpha release Introduces MetricsService as a new @alpha core service wrapping @opentelemetry/api. Includes migration of existing catalog metrics to use the new service. Signed-off-by: benjdlambert * chore: duplicate otel types, add plugin-scoped factory and tests Signed-off-by: benjdlambert * chore: update BEP-0012 metrics service design Signed-off-by: Kurt King * chore: address PR feedback from freben and rugvip Rename instrument types with MetricsService prefix for namespace clarity, move config to backend.metrics.plugin.{pluginId}, add config.d.ts schema, and improve factory test assertions. Signed-off-by: benjdlambert --------- Signed-off-by: benjdlambert Signed-off-by: Kurt King Co-authored-by: Kurt King --- .changeset/ninety-corners-flash.md | 5 + .changeset/rare-adults-attack.md | 6 + .changeset/twenty-worlds-create.md | 5 + beps/0012-metrics-service/README.md | 69 +++-- packages/backend-defaults/config.d.ts | 30 ++ packages/backend-defaults/report-alpha.api.md | 8 + .../backend-defaults/src/CreateBackend.ts | 2 + .../metrics/DefaultMetricsService.test.ts | 117 ++++++++ .../metrics/DefaultMetricsService.ts | 123 ++++++++ .../src/alpha/entrypoints/metrics/index.ts | 16 + .../metrics/metricsServiceFactory.test.ts | 130 +++++++++ .../metrics/metricsServiceFactory.ts | 48 +++ packages/backend-defaults/src/alpha/index.ts | 1 + .../backend-plugin-api/report-alpha.api.md | 144 +++++++++ .../src/alpha/MetricsService.ts | 273 ++++++++++++++++++ .../backend-plugin-api/src/alpha/index.ts | 19 ++ packages/backend-plugin-api/src/alpha/refs.ts | 11 + .../backend-test-utils/report-alpha.api.md | 11 + .../src/alpha/services/MetricsServiceMock.ts | 59 ++++ .../src/alpha/services/index.ts | 1 + .../src/wiring/TestBackend.ts | 2 + .../DefaultProcessingDatabase.test.ts | 2 + .../src/database/DefaultProcessingDatabase.ts | 5 +- .../catalog-backend/src/database/metrics.ts | 12 +- .../DefaultCatalogProcessingEngine.test.ts | 10 + .../DefaultCatalogProcessingEngine.ts | 17 +- .../src/service/CatalogBuilder.ts | 6 + .../src/service/CatalogPlugin.ts | 13 +- .../src/service/DefaultRefreshService.test.ts | 4 + .../src/stitching/DefaultStitcher.test.ts | 2 + .../src/stitching/DefaultStitcher.ts | 10 +- .../src/stitching/progressTracker.ts | 18 +- .../src/tests/integration.test.ts | 4 + .../getProcessableEntitiesPerformance.test.ts | 2 + 34 files changed, 1121 insertions(+), 64 deletions(-) create mode 100644 .changeset/ninety-corners-flash.md create mode 100644 .changeset/rare-adults-attack.md create mode 100644 .changeset/twenty-worlds-create.md create mode 100644 packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.test.ts create mode 100644 packages/backend-defaults/src/alpha/entrypoints/metrics/DefaultMetricsService.ts create mode 100644 packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts create mode 100644 packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.test.ts create mode 100644 packages/backend-defaults/src/alpha/entrypoints/metrics/metricsServiceFactory.ts create mode 100644 packages/backend-plugin-api/src/alpha/MetricsService.ts create mode 100644 packages/backend-test-utils/src/alpha/services/MetricsServiceMock.ts 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/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/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/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/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/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/backend-defaults/src/alpha/entrypoints/metrics/index.ts b/packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts new file mode 100644 index 0000000000..fc3e04a855 --- /dev/null +++ b/packages/backend-defaults/src/alpha/entrypoints/metrics/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +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-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/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/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/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/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 a032fd732e..915dd80dd9 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -43,10 +43,12 @@ import { } from '@backstage/plugin-catalog-node/alpha'; import { eventsServiceRef } from '@backstage/plugin-events-node'; import { Permission } from '@backstage/plugin-permission-common'; -import { metrics } from '@opentelemetry/api'; 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'; @@ -220,6 +222,7 @@ export const catalogPlugin = createBackendPlugin({ catalog: catalogServiceRef, actionsRegistry: actionsRegistryServiceRef, catalogScmEvents: catalogScmEventsServiceRef, + metrics: metricsServiceRef, }, async init({ logger, @@ -238,6 +241,7 @@ export const catalogPlugin = createBackendPlugin({ auditor, events, catalogScmEvents, + metrics, }) { const builder = await CatalogBuilder.create({ config, @@ -252,6 +256,7 @@ export const catalogPlugin = createBackendPlugin({ auditor, events, catalogScmEvents, + metrics, }); if (onProcessingError) { @@ -303,9 +308,7 @@ export const catalogPlugin = createBackendPlugin({ actionsRegistry, }); - // Track SCM event message counts as a metric - const meter = metrics.getMeter('default'); - const scmEventsMessagesCounter = meter.createCounter<{ + const scmEventsMessagesCounter = metrics.createCounter<{ eventType: string; }>('catalog.events.scm.messages', { description: 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/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(); From dc81af158f3ec81acd6e4bf7dd73e27b625f2cfe Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Tue, 24 Feb 2026 17:18:02 +0100 Subject: [PATCH 53/62] feat(mcp-actions): add server operation and session duration metrics (#32978) Signed-off-by: Kurt King Co-authored-by: Kurt King --- .changeset/swift-ravens-jog.md | 8 + plugins/mcp-actions-backend/README.md | 9 +- plugins/mcp-actions-backend/src/metrics.ts | 73 ++++++++ .../mcp-actions-backend/src/plugin.test.ts | 2 + plugins/mcp-actions-backend/src/plugin.ts | 5 + .../src/routers/createStreamableRouter.ts | 37 ++++ .../src/services/McpService.test.ts | 150 +++++++++++++++- .../src/services/McpService.ts | 160 +++++++++++++----- 8 files changed, 395 insertions(+), 49 deletions(-) create mode 100644 .changeset/swift-ravens-jog.md create mode 100644 plugins/mcp-actions-backend/src/metrics.ts 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/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/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; From 890935951bab4498c8d88ff3115e3fbffbf175b0 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Tue, 24 Feb 2026 17:28:32 +0100 Subject: [PATCH 54/62] fix(ui): CSS accessibility fixes for Menu, Select, and RadioGroup (#32983) * fix(ui): add focus-visible outlines to Menu and Select Replace the default browser focus-visible outline with a consistent ring style using the data-focus-visible attribute on Menu items and Select options. Signed-off-by: Johan Persson * fix(ui): add cursor styles to RadioGroup items Add pointer cursor to radio items and not-allowed cursor for readonly state. Signed-off-by: Johan Persson --------- Signed-off-by: Johan Persson --- .changeset/mean-fans-decide.md | 7 +++++++ .changeset/silver-pigs-remain.md | 7 +++++++ packages/ui/src/components/Menu/Menu.module.css | 9 +++++++++ .../ui/src/components/RadioGroup/RadioGroup.module.css | 5 +++++ packages/ui/src/components/Select/Select.module.css | 5 +++++ 5 files changed, 33 insertions(+) create mode 100644 .changeset/mean-fans-decide.md create mode 100644 .changeset/silver-pigs-remain.md 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/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/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; From 4bd6a3a1afd007b1d87359de5ea74dce7288021f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 24 Feb 2026 19:24:06 +0000 Subject: [PATCH 55/62] Version Packages (next) --- .changeset/pre.json | 40 +- docs/releases/v1.49.0-next.0-changelog.md | 2362 +++++++++++++++++ package.json | 2 +- packages/app-defaults/CHANGELOG.md | 11 + packages/app-defaults/package.json | 2 +- packages/app-example-plugin/CHANGELOG.md | 8 + packages/app-example-plugin/package.json | 2 +- packages/app-legacy/CHANGELOG.md | 44 + packages/app-legacy/package.json | 2 +- packages/app/CHANGELOG.md | 50 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 9 + packages/backend-app-api/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 25 + packages/backend-defaults/package.json | 2 +- .../CHANGELOG.md | 26 + .../package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 9 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 14 + packages/backend-plugin-api/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 16 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 42 + packages/backend/package.json | 2 +- packages/catalog-client/CHANGELOG.md | 10 + packages/catalog-client/package.json | 2 +- packages/cli-common/CHANGELOG.md | 34 + packages/cli-common/package.json | 2 +- packages/cli-node/CHANGELOG.md | 11 + packages/cli-node/package.json | 2 +- packages/cli/CHANGELOG.md | 29 + packages/cli/package.json | 2 +- packages/codemods/CHANGELOG.md | 9 + packages/codemods/package.json | 2 +- packages/config-loader/CHANGELOG.md | 11 + packages/config-loader/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 10 + packages/core-app-api/package.json | 2 +- packages/core-compat-api/CHANGELOG.md | 12 + packages/core-compat-api/package.json | 2 +- packages/core-components/CHANGELOG.md | 11 + packages/core-components/package.json | 2 +- packages/core-plugin-api/CHANGELOG.md | 11 + packages/core-plugin-api/package.json | 2 +- packages/create-app/CHANGELOG.md | 9 + packages/create-app/package.json | 2 +- packages/dev-utils/CHANGELOG.md | 15 + packages/dev-utils/package.json | 2 +- packages/e2e-test/CHANGELOG.md | 9 + packages/e2e-test/package.json | 2 +- packages/eslint-plugin/CHANGELOG.md | 6 + packages/eslint-plugin/package.json | 2 +- packages/frontend-app-api/CHANGELOG.md | 14 + packages/frontend-app-api/package.json | 2 +- packages/frontend-defaults/CHANGELOG.md | 12 + packages/frontend-defaults/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- packages/frontend-internal/CHANGELOG.md | 9 + packages/frontend-internal/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 10 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 19 + packages/frontend-test-utils/package.json | 2 +- packages/integration-react/CHANGELOG.md | 9 + packages/integration-react/package.json | 2 +- packages/integration/CHANGELOG.md | 12 + packages/integration/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 17 + packages/repo-tools/package.json | 2 +- packages/scaffolder-internal/CHANGELOG.md | 8 + packages/scaffolder-internal/package.json | 2 +- .../techdocs-cli-embedded-app/CHANGELOG.md | 21 + .../techdocs-cli-embedded-app/package.json | 2 +- packages/techdocs-cli/CHANGELOG.md | 13 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 13 + packages/test-utils/package.json | 2 +- packages/ui/CHANGELOG.md | 17 + packages/ui/package.json | 2 +- packages/yarn-plugin/CHANGELOG.md | 9 + packages/yarn-plugin/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 15 + plugins/api-docs/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 13 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 8 + plugins/app-node/package.json | 2 +- plugins/app-react/CHANGELOG.md | 8 + plugins/app-react/package.json | 2 +- plugins/app-visualizer/CHANGELOG.md | 10 + plugins/app-visualizer/package.json | 2 +- plugins/app/CHANGELOG.md | 17 + plugins/app/package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 15 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 12 + plugins/auth-node/package.json | 2 +- plugins/auth-react/CHANGELOG.md | 9 + plugins/auth-react/package.json | 2 +- plugins/auth/CHANGELOG.md | 10 + plugins/auth/package.json | 2 +- plugins/bitbucket-cloud-common/CHANGELOG.md | 7 + plugins/bitbucket-cloud-common/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 16 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 11 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../catalog-backend-module-gcp/CHANGELOG.md | 11 + .../catalog-backend-module-gcp/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../catalog-backend-module-gitea/CHANGELOG.md | 12 + .../catalog-backend-module-gitea/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 13 + .../catalog-backend-module-ldap/package.json | 2 +- .../catalog-backend-module-logs/CHANGELOG.md | 9 + .../catalog-backend-module-logs/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 30 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 13 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 21 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 22 + plugins/catalog-react/package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 13 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 25 + plugins/catalog/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 10 + plugins/config-schema/package.json | 2 +- plugins/devtools-backend/CHANGELOG.md | 15 + plugins/devtools-backend/package.json | 2 +- plugins/devtools-react/CHANGELOG.md | 8 + plugins/devtools-react/package.json | 2 +- plugins/devtools/CHANGELOG.md | 14 + plugins/devtools/package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../events-backend-module-azure/CHANGELOG.md | 8 + .../events-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../CHANGELOG.md | 8 + .../package.json | 2 +- .../events-backend-module-gerrit/CHANGELOG.md | 8 + .../events-backend-module-gerrit/package.json | 2 +- .../events-backend-module-github/CHANGELOG.md | 11 + .../events-backend-module-github/package.json | 2 +- .../events-backend-module-gitlab/CHANGELOG.md | 9 + .../events-backend-module-gitlab/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../events-backend-module-kafka/CHANGELOG.md | 10 + .../events-backend-module-kafka/package.json | 2 +- .../events-backend-test-utils/CHANGELOG.md | 7 + .../events-backend-test-utils/package.json | 2 +- plugins/events-backend/CHANGELOG.md | 12 + plugins/events-backend/package.json | 2 +- plugins/events-node/CHANGELOG.md | 9 + plugins/events-node/package.json | 2 +- .../example-todo-list-backend/CHANGELOG.md | 8 + .../example-todo-list-backend/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 8 + plugins/example-todo-list/package.json | 2 +- plugins/gateway-backend/CHANGELOG.md | 7 + plugins/gateway-backend/package.json | 2 +- plugins/home-react/CHANGELOG.md | 10 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 17 + plugins/home/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 18 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 13 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 10 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 12 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 14 + plugins/kubernetes/package.json | 2 +- plugins/mcp-actions-backend/CHANGELOG.md | 16 + plugins/mcp-actions-backend/package.json | 2 +- plugins/mui-to-bui/CHANGELOG.md | 10 + plugins/mui-to-bui/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- plugins/notifications-backend/CHANGELOG.md | 15 + plugins/notifications-backend/package.json | 2 +- plugins/notifications-node/CHANGELOG.md | 11 + plugins/notifications-node/package.json | 2 +- plugins/notifications/CHANGELOG.md | 13 + plugins/notifications/package.json | 2 +- plugins/org-react/CHANGELOG.md | 11 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 12 + plugins/org/package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/permission-backend/CHANGELOG.md | 12 + plugins/permission-backend/package.json | 2 +- plugins/permission-node/CHANGELOG.md | 11 + plugins/permission-node/package.json | 2 +- plugins/permission-react/CHANGELOG.md | 9 + plugins/permission-react/package.json | 2 +- plugins/proxy-backend/CHANGELOG.md | 9 + plugins/proxy-backend/package.json | 2 +- plugins/proxy-node/CHANGELOG.md | 7 + plugins/proxy-node/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 20 + plugins/scaffolder-backend/package.json | 2 +- plugins/scaffolder-common/CHANGELOG.md | 11 + plugins/scaffolder-common/package.json | 2 +- .../scaffolder-node-test-utils/CHANGELOG.md | 10 + .../scaffolder-node-test-utils/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 13 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 17 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 24 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 10 + plugins/search-backend-module-pg/package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- plugins/search-backend-node/CHANGELOG.md | 11 + plugins/search-backend-node/package.json | 2 +- plugins/search-backend/CHANGELOG.md | 15 + plugins/search-backend/package.json | 2 +- plugins/search-react/CHANGELOG.md | 14 + plugins/search-react/package.json | 2 +- plugins/search/CHANGELOG.md | 16 + plugins/search/package.json | 2 +- plugins/signals-backend/CHANGELOG.md | 11 + plugins/signals-backend/package.json | 2 +- plugins/signals-node/CHANGELOG.md | 11 + plugins/signals-node/package.json | 2 +- plugins/signals-react/CHANGELOG.md | 8 + plugins/signals-react/package.json | 2 +- plugins/signals/CHANGELOG.md | 12 + plugins/signals/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 15 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 15 + plugins/techdocs-backend/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 14 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 13 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 22 + plugins/techdocs/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 12 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 17 + plugins/user-settings/package.json | 2 +- 369 files changed, 4936 insertions(+), 185 deletions(-) create mode 100644 docs/releases/v1.49.0-next.0-changelog.md 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/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/package.json b/package.json index a0a530adb8..a6a5ca8084 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/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-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-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-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/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/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 4eae1d96a4..4e38607467 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,6 +1,6 @@ { "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" 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/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/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/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/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/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-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/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/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/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-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/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 bc27ae4a42..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" 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/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/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/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/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/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/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-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-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-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 b06bd8ca08..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", 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-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/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/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/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/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/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/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-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-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/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/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/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/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", From 6a1c9550b5ae34e37a834f3ae7fad0a214e73905 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:01:03 +0100 Subject: [PATCH 56/62] repo: migrate to AGENTS.md Move agent instructions from `.github/copilot-instructions.md` to `AGENTS.md` at the repo root for broader AI agent tool compatibility, and remove the Cursor rule that pointed at the old file. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .cursor/rules/general.mdc | 7 ----- .github/copilot-instructions.md | 46 --------------------------------- AGENTS.md | 45 ++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 53 deletions(-) delete mode 100644 .cursor/rules/general.mdc create mode 100644 AGENTS.md 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/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..ebf597cecc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +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. From 410e867616953b001383760ab2f68584a38b5dfe Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:12:09 +0100 Subject: [PATCH 57/62] AGENTS.md: some more pointers for changesets and code style Signed-off-by: Patrik Oldsberg --- AGENTS.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index ebf597cecc..b4372229d8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,10 @@ The following files contain guidelines for the project: - `/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. @@ -36,10 +40,14 @@ Before any of these commands can be run, you need to run `yarn install` in the p 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. +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, 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. From 60cdf5b80cb59826903b50a6e76f4f8d64938a33 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:14:27 +0100 Subject: [PATCH 58/62] repo: expand AGENTS.md with additional guidelines Add coding style, testing, changeset, and PR template guidelines. Remove the now-redundant .claude/CLAUDE.md pointer file. Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .claude/CLAUDE.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .claude/CLAUDE.md 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 From 614f524ace82d77b28def1fcc0dc8c575f8abc90 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:48:12 +0100 Subject: [PATCH 59/62] AGENTS.md: minor for significant changes only Signed-off-by: Patrik Oldsberg --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index b4372229d8..fc8468b98c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,7 @@ Before any of these commands can be run, you need to run `yarn install` in the p 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 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, 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. +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`. From 9657061e648b7241089ddb914369581ef493e96d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:50:16 +0100 Subject: [PATCH 60/62] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- AGENTS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fc8468b98c..001989d9b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,15 +30,15 @@ When writing or generating tests, prefer fewer thorough tests with multiple asse 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. +- 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 create a release by running `yarn changesets version` or `yarn release` as part of any changes. Releases are created by separate workflows. +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. From 560f5876453fab5c92d885a9f351218587328262 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Feb 2026 21:57:52 +0100 Subject: [PATCH 61/62] repo: symlink .claude/CLAUDE.md to AGENTS.md Signed-off-by: Patrik Oldsberg Co-authored-by: Cursor --- .claude/CLAUDE.md | 1 + 1 file changed, 1 insertion(+) create mode 120000 .claude/CLAUDE.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 From 2e1f98b687ffed78c51c5431acaff2e2718cc34b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 05:24:30 +0000 Subject: [PATCH 62/62] build(deps): bump minimatch from 3.1.2 to 10.2.3 Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 10.2.3. - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v10.2.3) --- updated-dependencies: - dependency-name: minimatch dependency-version: 10.2.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 2a41ca71e4..14a3f7453e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39425,7 +39425,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:10.2.1, minimatch@npm:^10.1.1, minimatch@npm:^10.2.0, minimatch@npm:^10.2.1": +"minimatch@npm:10.2.1": version: 10.2.1 resolution: "minimatch@npm:10.2.1" dependencies: @@ -39452,6 +39452,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.1.1, minimatch@npm:^10.2.0, minimatch@npm:^10.2.1": + version: 10.2.3 + resolution: "minimatch@npm:10.2.3" + dependencies: + brace-expansion: "npm:^5.0.2" + checksum: 10/186c6a6ce9f7a79ae7776efc799c32d1a6670ebbcc2a8756e6cb6ec4aab7439a6ca6e592e1a6aac5f21674eefae5b19821b8fa95072a4f4567da1ae40eb6075d + languageName: node + linkType: hard + "minimatch@npm:^5.0.1, minimatch@npm:^5.1.0": version: 5.1.6 resolution: "minimatch@npm:5.1.6"