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 <poldsberg@gmail.com>
This commit is contained in:
@@ -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')
|
||||
```
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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<typeof import('@backstage/cli-common')>(
|
||||
'@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<string, ScannedPluginManifest>([
|
||||
[
|
||||
|
||||
@@ -56,7 +56,7 @@ export class DynamicPluginManager implements DynamicPluginProvider {
|
||||
options: DynamicPluginManagerOptions,
|
||||
): Promise<DynamicPluginManager> {
|
||||
/* 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,
|
||||
|
||||
@@ -100,7 +100,7 @@ const dynamicPluginsSchemasServiceFactoryWithOptions = (
|
||||
config,
|
||||
logger,
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
backstageRoot: targetPaths.resolveRoot(),
|
||||
backstageRoot: targetPaths.rootDir,
|
||||
preferAlpha: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -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<string>;
|
||||
|
||||
// @public
|
||||
export type TargetPaths = {
|
||||
dir: string;
|
||||
rootDir: string;
|
||||
resolve: ResolveFunc;
|
||||
resolveRoot: ResolveFunc;
|
||||
};
|
||||
|
||||
// @public
|
||||
export const targetPaths: TargetPaths;
|
||||
```
|
||||
|
||||
+140
-115
@@ -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<string, string>();
|
||||
|
||||
// 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<string, string>();
|
||||
|
||||
function getTargetDir(): string {
|
||||
const cwd = process.cwd();
|
||||
if (cachedTargetDir !== undefined && cachedTargetCwd === cwd) {
|
||||
return cachedTargetDir;
|
||||
class OwnPathsImpl implements OwnPaths {
|
||||
static #instanceCache = new Map<string, OwnPathsImpl>();
|
||||
|
||||
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<string, OwnPaths>();
|
||||
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<string, OwnPaths>();
|
||||
* 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
@@ -47,14 +47,14 @@ export async function command(opts: OptionValues): Promise<void> {
|
||||
|
||||
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<void> {
|
||||
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,
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function command(opts: OptionValues): Promise<void> {
|
||||
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),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise<void> {
|
||||
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,
|
||||
};
|
||||
|
||||
@@ -117,7 +117,7 @@ export async function makeRollupConfigs(
|
||||
options: BuildOptions,
|
||||
): Promise<RollupOptions[]> {
|
||||
const configs = new Array<RollupOptions>();
|
||||
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'),
|
||||
),
|
||||
]),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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.')) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -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)]),
|
||||
});
|
||||
|
||||
|
||||
@@ -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<string, string>();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -63,7 +63,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise<void> {
|
||||
|
||||
// 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<void> {
|
||||
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<void> {
|
||||
shouldCache: Boolean(cacheContext),
|
||||
maxWarnings: opts.maxWarnings ?? -1,
|
||||
successCache: cacheContext?.entries,
|
||||
rootDir: targetPaths.resolveRoot(),
|
||||
rootDir: targetPaths.rootDir,
|
||||
},
|
||||
workerFactory: async ({
|
||||
fix,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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'),
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -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<string, PkgVersionInfo[]>();
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export async function collectPortableTemplateInput(
|
||||
): Promise<PortableTemplateInput> {
|
||||
const { config, template, prefilledParams } = options;
|
||||
|
||||
const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.resolveRoot());
|
||||
const codeOwnersFilePath = await getCodeownersFilePath(targetPaths.rootDir);
|
||||
|
||||
const prompts = getPromptsForRole(template.role);
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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[]) =>
|
||||
|
||||
@@ -76,8 +76,8 @@ export default async (opts: OptionValues): Promise<void> => {
|
||||
// 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<void> => {
|
||||
// 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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
+3
-3
@@ -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<void>} 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) {
|
||||
|
||||
+2
-2
@@ -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`,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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/*'] },
|
||||
}),
|
||||
|
||||
@@ -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'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:`,
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:`,
|
||||
);
|
||||
|
||||
@@ -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 });
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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`)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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}\`.`,
|
||||
);
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}),
|
||||
|
||||
@@ -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'),
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user