refactor: apply review suggestions

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2025-09-24 13:58:35 +02:00
parent ab96bb770f
commit 8a16781eba
7 changed files with 120 additions and 16 deletions
+3 -5
View File
@@ -2,7 +2,7 @@
'@backstage/cli': patch
---
Added a new `--entry-dir` option to the `package start` command, which allows you to specify a custom entry directory for development applications. This is particularly useful when maintaining separate dev apps for different versions of your plugin (e.g., stable and alpha).
Added a new `--entrypoint` option to the `package start` command, which allows you to specify a custom entry directory/file for development applications. This is particularly useful when maintaining separate dev apps for different versions of your plugin (e.g., stable and alpha).
**Example usage:**
@@ -15,7 +15,5 @@ dev/
index.ts
```
- The default `yarn package start` command uses the `dev/` folder as the entry point and executes `dev/index.tsx`
- Running `yarn package start --entry-dir dev/alpha` will instead use `dev/alpha/` as the entry point and execute `dev/alpha/index.ts`
This enables you to maintain multiple development environments within a single plugin package.
- The default `yarn package start` command uses the `dev/` folder as the entry point and executes `dev/index.tsx` file;
- Running `yarn package start --entrypoint dev/alpha` will instead use `dev/alpha/` as the entry point and execute `dev/alpha/index.ts` file.
+6 -6
View File
@@ -177,12 +177,12 @@ Usage: backstage-cli package start [options]
Start a package for local development
Options:
--config <path> Config files to load instead of app-config.yaml (default: [])
--role <name> Run the command with an explicit package role
--check Enable type checking and linting if available
--inspect Enable debugger in Node.js environments
--inspect-brk Enable debugger in Node.js environments, breaking before code starts
--entry-dir <path> Path to the directory containing the entry point file
--config <path> Config files to load instead of app-config.yaml (default: [])
--role <name> Run the command with an explicit package role
--check Enable type checking and linting if available
--inspect Enable debugger in Node.js environments
--inspect-brk Enable debugger in Node.js environments, breaking before code starts
--entrypoint <path> Entry directory path (uses index file) or entry file path (without extension). Defaults to "dev"
```
## package build
+1
View File
@@ -312,6 +312,7 @@ Usage: program [options]
Options:
--check
--config <path>
--entrypoint <path>
--inspect [host]
--inspect-brk [host]
--link <path>
@@ -23,7 +23,7 @@ import { paths } from '../../../../../lib/paths';
export async function command(opts: OptionValues): Promise<void> {
await startPackage({
role: await findRoleFromCommand(opts),
entryDir: opts.entryDir,
entrypoint: opts.entrypoint,
targetDir: paths.targetDir,
configPaths: opts.config as string[],
checksEnabled: Boolean(opts.check),
@@ -0,0 +1,89 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createMockDirectory } from '@backstage/backend-test-utils';
import { resolveEntryPath } from './startPackage';
describe('resolveEntryPath', () => {
const mockDir = createMockDirectory();
afterEach(() => {
mockDir.clear();
});
it('should remove file extensions', () => {
mockDir.setContent({
'dev/custom.tsx': '// dev app code',
});
const result = resolveEntryPath('dev/custom.tsx', mockDir.path);
expect(result).toBe('dev/custom');
});
it('should remove trailing slashes', () => {
mockDir.setContent({
'dev/alpha.ts': '// dev app code',
});
const result = resolveEntryPath('dev/alpha/', mockDir.path);
expect(result).toBe('dev/alpha');
});
it('should handle multiple dots in filename', () => {
mockDir.setContent({
'file.backup.old.ts': 'export const data = {};',
});
const result = resolveEntryPath('file.backup.old.ts', mockDir.path);
expect(result).toBe('file.backup.old');
});
it('should handle simple directory names', () => {
mockDir.setContent({
'dev/index.ts': '// dev app code',
});
const result = resolveEntryPath('dev', mockDir.path);
expect(result).toBe('dev/index');
});
it('should handle nested directory paths', () => {
mockDir.setContent({
'dev/alpha/index.ts': '// dev app code',
});
const result = resolveEntryPath('dev/alpha', mockDir.path);
expect(result).toBe('dev/alpha/index');
});
it('should return the file when there is a directory with the same name', () => {
mockDir.setContent({
'dev/alpha.ts': '// dev app code',
'dev/app-config.yaml': '// dev app config',
'dev/alpha/index.ts': '// dev app code',
'dev/alpha/app-config.yaml': '// dev app config',
});
const result = resolveEntryPath('dev/alpha', mockDir.path);
expect(result).toBe('dev/alpha');
});
});
@@ -17,10 +17,26 @@
import { PackageRole } from '@backstage/cli-node';
import { startBackend, startBackendPlugin } from './startBackend';
import { startFrontend } from './startFrontend';
import { statSync, readdirSync } from 'fs';
import { resolve, join, parse } from 'path';
export function resolveEntryPath(
entrypoint: string = 'dev',
targetDir: string,
): string {
const { dir: entryDir, name: entryName } = parse(entrypoint);
const entryPath = join(entryDir, entryName);
const parentPath = resolve(targetDir, entryDir);
const isFile = readdirSync(parentPath).some(base => {
const path = resolve(parentPath, base);
return statSync(path).isFile();
});
return isFile ? entryPath : join(entryPath, 'index');
}
export async function startPackage(options: {
role: PackageRole;
entryDir: string;
entrypoint?: string;
targetDir: string;
configPaths: string[];
checksEnabled: boolean;
@@ -47,7 +63,7 @@ export async function startPackage(options: {
case 'frontend-plugin-module':
return startFrontend({
...options,
entry: `${options.entryDir ?? 'dev'}/index`,
entry: resolveEntryPath(options.entrypoint, options.targetDir),
});
case 'frontend-dynamic-container' as PackageRole: // experimental
return startFrontend({
+2 -2
View File
@@ -138,8 +138,8 @@ export const buildPlugin = createCliPlugin({
'Link an external workspace for module resolution',
)
.option(
'--entry-dir <path>',
'Path to the directory containing the entry point file',
'--entrypoint <path>',
'Entry directory path (uses index file) or entry file path (without extension). Defaults to "dev"',
)
.action(lazy(() => import('./commands/package/start'), 'command'));