From 29e91e9159dae1a83456d35958651a1fd9aa42a0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 21 Feb 2026 13:16:50 +0100 Subject: [PATCH] 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);