merge with master and resolve yarn.lock conflict

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-04-01 16:39:43 +02:00
2168 changed files with 66702 additions and 13541 deletions
+132
View File
@@ -1,5 +1,137 @@
# @backstage/cli
## 0.26.2
### Patch Changes
- eeb226a: Updated dependency `rollup` to `^4.0.0`.
- 91192f4: Updated backend plugin template to work better with new backend system
- cc371d6: Ignore transforming only on `react-use/lib`, not whole `react-use` in jest.
** POTENTIAL BREAKAGE **
If your tests fail, please change to use path import from `react-use/esm/`. It is also recommended to migrate from `react-user/lib` imports to `react-use/esm`
- Updated dependencies
- @backstage/catalog-model@1.4.5
- @backstage/cli-common@0.1.13
- @backstage/cli-node@0.2.4
- @backstage/config@1.2.0
- @backstage/config-loader@1.7.0
- @backstage/errors@1.2.4
- @backstage/eslint-plugin@0.1.6
- @backstage/integration@1.9.1
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.26.1
### Patch Changes
- eeb226a: Updated dependency `rollup` to `^4.0.0`.
- cc371d6: Ignore transforming only on `react-use/lib`, not whole `react-use` in jest.
** POTENTIAL BREAKAGE **
If your tests fail, please change to use path import from `react-use/esm/`. It is also recommended to migrate from `react-user/lib` imports to `react-use/esm`
- Updated dependencies
- @backstage/catalog-model@1.4.5
- @backstage/cli-common@0.1.13
- @backstage/cli-node@0.2.4
- @backstage/config@1.2.0
- @backstage/config-loader@1.7.0
- @backstage/errors@1.2.4
- @backstage/eslint-plugin@0.1.6
- @backstage/integration@1.9.1
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.26.0
### Minor Changes
- 0d72065: The backend devlopment server transpilation has been replaced with a simplified solution based on SWC, which is already the transpiler used for tests. This fixed an issue where never versions of the `tsx` dependency had a new contract for signalling dependencies, breaking watch mode. This change fixed file watches as well as enables sourcemaps.
### Patch Changes
- fe1a55e: Extend option to minify generated code to the `backend` package.
- b0875e5: Fixed a bug that could cause the `build-workspace` command to fail when invoked with `--alwaysYarnPack` enabled in environments with limited resources.
- bdf9ec1: New backend plugins with cli are now created using the new backend system
- cadbb82: Added a `EXPERIMENTAL_LAZY_COMPILATION` flag, which enables the experimental Webpack lazy compilation option in frontend builds.
- 999224f: Bump dependency `minimatch` to v9
- 1bd4596: Removed the `ts-node` dev dependency.
- 8dce287: Fix prettier issues on default plugins & module templates
- f86e34c: Removed unused `replace-in-file` dependency
- 2398c7c: Updated dependency `@spotify/prettier-config` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-base` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-react` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-typescript` to `^15.0.0`.
- f4404e5: Add .ico import support
- f39dfd3: Tweak the descriptions of the CLI templates
- Updated dependencies
- @backstage/integration@1.9.1
- @backstage/config@1.2.0
- @backstage/errors@1.2.4
- @backstage/eslint-plugin@0.1.6
- @backstage/config-loader@1.7.0
- @backstage/cli-node@0.2.4
- @backstage/catalog-model@1.4.5
- @backstage/cli-common@0.1.13
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.25.3-next.2
### Patch Changes
- f39dfd3: Tweak the descriptions of the CLI templates
- Updated dependencies
- @backstage/integration@1.9.1-next.2
- @backstage/catalog-model@1.4.5-next.0
- @backstage/cli-common@0.1.13
- @backstage/cli-node@0.2.4-next.0
- @backstage/config@1.2.0-next.1
- @backstage/config-loader@1.7.0-next.1
- @backstage/errors@1.2.4-next.0
- @backstage/eslint-plugin@0.1.6-next.0
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.25.3-next.1
### Patch Changes
- 8dce287: Fix prettier issues on default plugins & module templates
- Updated dependencies
- @backstage/config@1.2.0-next.1
- @backstage/config-loader@1.7.0-next.1
- @backstage/integration@1.9.1-next.1
- @backstage/catalog-model@1.4.5-next.0
- @backstage/cli-common@0.1.13
- @backstage/cli-node@0.2.4-next.0
- @backstage/errors@1.2.4-next.0
- @backstage/eslint-plugin@0.1.6-next.0
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.25.3-next.0
### Patch Changes
- 999224f: Bump dependency `minimatch` to v9
- f86e34c: Removed unused `replace-in-file` dependency
- f4404e5: Add .ico import support
- Updated dependencies
- @backstage/errors@1.2.4-next.0
- @backstage/eslint-plugin@0.1.6-next.0
- @backstage/cli-node@0.2.4-next.0
- @backstage/config-loader@1.6.3-next.0
- @backstage/catalog-model@1.4.5-next.0
- @backstage/config@1.1.2-next.0
- @backstage/integration@1.9.1-next.0
- @backstage/cli-common@0.1.13
- @backstage/release-manifests@0.0.11
- @backstage/types@1.1.1
## 0.25.2
### Patch Changes
+1 -9
View File
@@ -24,14 +24,6 @@ const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
require('..');
} else {
require('ts-node').register({
transpileOnly: true,
/* eslint-disable-next-line no-restricted-syntax */
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
},
});
require('@backstage/cli/config/nodeTransform.cjs');
require('../src');
}
+1 -1
View File
@@ -43,7 +43,7 @@ const transformIgnorePattern = [
'highlight\\.js',
'prismjs',
'json-schema',
'react-use',
'react-use/lib',
'typescript',
].join('|');
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright 2024 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.
*/
const { transformSync } = require('@swc/core');
const { addHook } = require('pirates');
addHook(
(code, filename) => {
const transformed = transformSync(code, {
filename,
sourceMaps: 'inline',
module: { type: 'commonjs' },
jsc: {
target: 'es2022',
parser: {
syntax: 'typescript',
},
},
});
process.send?.({ type: 'watch', path: filename });
return transformed.code;
},
{ extensions: ['.ts', '.cts'], ignoreNodeModules: true },
);
addHook(
(code, filename) => {
process.send?.({ type: 'watch', path: filename });
return code;
},
{ extensions: ['.js', '.cjs'], ignoreNodeModules: true },
);
+2 -2
View File
@@ -25,6 +25,7 @@
| @swc/core | package.json | error |
| @swc/jest | package.json | error |
| esbuild | package.json | error |
| pirates | package.json | error |
| postcss | package.json | error |
| process | package.json | error |
| sucrase | package.json | error |
@@ -32,7 +33,7 @@
| glob | package.json | error |
| util | package.json | error |
## Unused devDependencies (12)
## Unused devDependencies (11)
| Name | Location | Severity |
| :-------------------------------------- | :----------- | :------- |
@@ -46,7 +47,6 @@
| @types/svgo | package.json | error |
| @types/ejs | package.json | error |
| nodemon | package.json | error |
| ts-node | package.json | error |
| del | package.json | error |
## Referenced optional peerDependencies (4)
+13 -9
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.25.2",
"version": "0.26.2",
"publishConfig": {
"access": "public"
},
@@ -50,9 +50,9 @@
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-yaml": "^4.0.0",
"@spotify/eslint-config-base": "^14.0.0",
"@spotify/eslint-config-react": "^14.0.0",
"@spotify/eslint-config-typescript": "^14.0.0",
"@spotify/eslint-config-base": "^15.0.0",
"@spotify/eslint-config-react": "^15.0.0",
"@spotify/eslint-config-typescript": "^15.0.0",
"@sucrase/webpack-loader": "^2.0.0",
"@svgr/core": "6.5.x",
"@svgr/plugin-jsx": "6.5.x",
@@ -112,15 +112,17 @@
"node-libs-browser": "^2.2.1",
"npm-packlist": "^5.0.0",
"ora": "^5.3.0",
"p-limit": "^3.1.0",
"p-queue": "^6.6.2",
"pirates": "^4.0.6",
"postcss": "^8.1.0",
"process": "^0.11.10",
"react-dev-utils": "^12.0.0-next.60",
"react-refresh": "^0.14.0",
"recursive-readdir": "^2.2.2",
"rollup": "^2.60.2",
"rollup-plugin-dts": "^4.0.1",
"rollup-plugin-esbuild": "^4.7.2",
"rollup": "^4.0.0",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-postcss": "^4.0.0",
"rollup-pluginutils": "^2.8.2",
"run-script-webpack-plugin": "^0.2.0",
@@ -130,7 +132,6 @@
"swc-loader": "^0.2.3",
"tar": "^6.1.12",
"terser-webpack-plugin": "^5.1.3",
"tsx": "^4.0.0",
"util": "^0.12.3",
"webpack": "^5.70.0",
"webpack-dev-server": "^5.0.0",
@@ -167,10 +168,13 @@
"@types/tar": "^6.1.1",
"@types/terser-webpack-plugin": "^5.0.4",
"@types/yarnpkg__lockfile": "^1.1.4",
"@vitejs/plugin-react": "^4.0.4",
"del": "^7.0.0",
"msw": "^1.0.0",
"nodemon": "^3.0.1",
"ts-node": "^10.0.0"
"vite": "^4.4.9",
"vite-plugin-html": "^3.2.0",
"vite-plugin-node-polyfills": "^0.21.0"
},
"peerDependencies": {
"@vitejs/plugin-react": "^4.0.4",
@@ -29,17 +29,19 @@ interface BuildBackendOptions {
targetDir: string;
skipBuildDependencies: boolean;
configPaths?: string[];
minify?: boolean;
}
export async function buildBackend(options: BuildBackendOptions) {
const { targetDir, skipBuildDependencies, configPaths } = options;
const { targetDir, skipBuildDependencies, configPaths, minify } = options;
const pkg = await fs.readJson(resolvePath(targetDir, 'package.json'));
// We build the target package without generating type declarations.
await buildPackage({
targetDir: options.targetDir,
targetDir,
packageJson: pkg,
outputs: new Set([Output.cjs]),
minify,
});
const tmpDir = await fs.mkdtemp(resolvePath(os.tmpdir(), 'backstage-bundle'));
@@ -51,6 +53,7 @@ export async function buildBackend(options: BuildBackendOptions) {
buildExcludes: [pkg.name],
parallelism: getEnvironmentParallelism(),
skeleton: SKELETON_FILE,
minify,
});
// We built the target backend package using the regular build process, but the result of
@@ -45,6 +45,7 @@ export async function command(opts: OptionValues): Promise<void> {
targetDir: paths.targetDir,
configPaths,
skipBuildDependencies: Boolean(opts.skipBuildDependencies),
minify: Boolean(opts.minify),
});
}
+1 -1
View File
@@ -128,7 +128,7 @@ export function registerScriptCommand(program: Command) {
.option('--role <name>', 'Run the command with an explicit package role')
.option(
'--minify',
'Minify the generated code. Does not apply to app or backend packages.',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.option(
'--skip-build-dependencies',
+1
View File
@@ -179,6 +179,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise<void> {
await buildBackend({
targetDir: pkg.dir,
skipBuildDependencies: true,
minify: buildOptions.minify,
});
},
});
+7 -2
View File
@@ -25,7 +25,11 @@ import svgr from '@svgr/rollup';
import dts from 'rollup-plugin-dts';
import json from '@rollup/plugin-json';
import yaml from '@rollup/plugin-yaml';
import { RollupOptions, OutputOptions, RollupWarning } from 'rollup';
import {
RollupOptions,
OutputOptions,
WarningHandlerWithDefault,
} from 'rollup';
import { forwardFileImports } from './plugins';
import { BuildOptions, Output } from './types';
@@ -61,7 +65,7 @@ export async function makeRollupConfigs(
targetPkg = (await fs.readJson(packagePath)) as BackstagePackageJson;
}
const onwarn = ({ code, message }: RollupWarning) => {
const onwarn: WarningHandlerWithDefault = ({ code, message }) => {
if (code === 'EMPTY_BUNDLE') {
return; // We don't care about this one
}
@@ -89,6 +93,7 @@ export async function makeRollupConfigs(
entryFileNames: `[name].cjs.js`,
chunkFileNames: `cjs/[name]-[hash].cjs.js`,
format: 'commonjs',
interop: 'compat',
sourcemap: true,
exports: 'named',
});
+3
View File
@@ -224,6 +224,9 @@ export async function createConfig(
}
: {}),
},
experiments: {
lazyCompilation: yn(process.env.EXPERIMENTAL_LAZY_COMPILATION),
},
plugins,
...(withCache
? {
@@ -22,22 +22,16 @@ import { ctrlc } from 'ctrlc-windows';
import { IpcServer } from './IpcServer';
import { ServerDataStore } from './ServerDataStore';
import debounce from 'lodash/debounce';
import { fileURLToPath, pathToFileURL } from 'url';
import { fileURLToPath } from 'url';
import { isAbsolute as isAbsolutePath } from 'path';
import { paths } from '../paths';
import spawn from 'cross-spawn';
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number);
const supportsModuleLoaderRegister =
nodeMajor > 20 ||
(nodeMajor === 20 && nodeMinor >= 6) ||
(nodeMajor === 18 && nodeMinor >= 19);
const loaderArgs = [
'--enable-source-maps',
'--require',
require.resolve('tsx/preflight'),
supportsModuleLoaderRegister ? '--import' : '--loader',
pathToFileURL(require.resolve('tsx')).toString(), // Windows prefers a URL here
require.resolve('@backstage/cli/config/nodeTransform.cjs'),
// TODO: Support modules, although there's currently no way to load them since import() is transpiled tp require()
];
export async function startBackendExperimental(options: BackendServeOptions) {
@@ -51,11 +45,21 @@ export async function startBackendExperimental(options: BackendServeOptions) {
ServerDataStore.bind(server);
let exiting = false;
let firstStart = true;
let child: ChildProcess | undefined;
let watcher: FSWatcher | undefined = undefined;
let shutdownPromise: Promise<void> | undefined = undefined;
const watchedPaths = new Set<string>();
const restart = debounce(async () => {
if (firstStart) {
firstStart = false;
} else {
console.log();
console.log('Change detected, restarting the development server...');
console.log();
}
// If a re-trigger happens during an existing shutdown, we just ignore it
if (shutdownPromise) {
return;
@@ -115,14 +119,18 @@ export async function startBackendExperimental(options: BackendServeOptions) {
// This captures messages sent by @esbuild-kit/cjs-loader
child.on('message', (data: { type?: string } | null) => {
if (typeof data === 'object' && data?.type === 'dependency') {
if (!watcher) {
return;
}
if (typeof data === 'object' && data?.type === 'watch') {
let path = (data as { path: string }).path;
if (path.startsWith('file:')) {
path = fileURLToPath(path);
}
if (isAbsolutePath(path)) {
watcher?.add(path);
if (isAbsolutePath(path) && !watchedPaths.has(path)) {
watchedPaths.add(path);
watcher.add(path);
}
}
});
@@ -130,7 +138,7 @@ export async function startBackendExperimental(options: BackendServeOptions) {
restart();
watcher = watch([], {
watcher = watch(['./package.json'], {
cwd: process.cwd(),
ignoreInitial: true,
ignorePermissionErrors: true,
@@ -38,7 +38,8 @@ type Options = {
export const backendModule = createFactory<Options>({
name: 'backend-module',
description: 'A new backend module',
description:
'A new backend module that extends an existing backend plugin with additional features',
optionsDiscovery: async () => ({
codeOwnersPath: await getCodeownersFilePath(paths.targetRoot),
}),
@@ -79,13 +79,13 @@ describe('backendPlugin factory', () => {
'Executing Template:',
'copying .eslintrc.js',
'templating README.md.hbs',
'templating index.ts.hbs',
'templating package.json.hbs',
'copying index.ts',
'templating run.ts.hbs',
'copying setupTests.ts',
'copying router.test.ts',
'copying router.ts',
'templating standaloneServer.ts.hbs',
'templating plugin.ts.hbs',
'Installing:',
`moving plugins${sep}test-backend`,
'backend adding dependency',
@@ -98,15 +98,6 @@ describe('backendPlugin factory', () => {
'backstage-plugin-test-backend': '^1.0.0',
},
});
const standaloneServerFile = await fs.readFile(
mockDir.resolve('plugins/test-backend/src/service/standaloneServer.ts'),
'utf-8',
);
expect(standaloneServerFile).toContain(
`const logger = options.logger.child({ service: 'test-backend' });`,
);
expect(standaloneServerFile).toContain(`.addRouter('/test', router);`);
expect(Task.forCommand).toHaveBeenCalledTimes(2);
expect(Task.forCommand).toHaveBeenCalledWith('yarn install', {
@@ -31,7 +31,8 @@ type Options = {
export const nodeLibraryPackage = createFactory<Options>({
name: 'node-library',
description: 'A new node-library package',
description:
'A new node-library package, exporting shared functionality for backend plugins and modules',
optionsDiscovery: async () => ({
codeOwnersPath: await getCodeownersFilePath(paths.targetRoot),
}),
@@ -31,7 +31,8 @@ type Options = {
export const webLibraryPackage = createFactory<Options>({
name: 'web-library',
description: 'A new web-library package',
description:
'A new web-library package, exporting shared functionality for frontend plugins',
optionsDiscovery: async () => ({
codeOwnersPath: await getCodeownersFilePath(paths.targetRoot),
}),
@@ -21,6 +21,7 @@ import {
resolve as resolvePath,
relative as relativePath,
} from 'path';
import pLimit from 'p-limit';
import { tmpdir } from 'os';
import tar, { CreateOptions, FileOptions } from 'tar';
import partition from 'lodash/partition';
@@ -102,6 +103,11 @@ type Options = {
* command performance.
*/
alwaysYarnPack?: boolean;
/**
* If set to true, the generated code will be minified.
*/
minify?: boolean;
};
function prefixLogFunc(prefix: string, out: 'stdout' | 'stderr') {
@@ -204,8 +210,7 @@ export async function createDistWorkspace(
packageJson: pkg.packageJson,
outputs: outputs,
logPrefix: `${chalk.cyan(relativePath(paths.targetRoot, pkg.dir))}: `,
// No need to detect these for the backend builds, we assume no minification or types
minify: false,
minify: options.minify,
});
}
}
@@ -352,9 +357,11 @@ async function moveToDistWorkspace(
}
// Repacking in parallel is much faster and safe for all packages outside of the Backstage repo
// Limit concurrency to 10 to avoid resource exhaustion on larger monorepos.
const limit = pLimit(10);
await Promise.all(
safePackages.map(async (target, index) =>
pack(target, `temp-package-${index}.tgz`),
safePackages.map((target, index) =>
limit(() => pack(target, `temp-package-${index}.tgz`)),
),
);
}
+7 -2
View File
@@ -20,7 +20,6 @@ import { paths } from './paths';
import { Lockfile } from './versioning';
/* eslint-disable @backstage/no-relative-monorepo-imports */
/*
This is a list of all packages used by the templates. If dependencies are added or removed,
this list should be updated as well.
@@ -33,7 +32,6 @@ This does not create an actual dependency on these packages and does not bring i
Rollup will extract the value of the version field in each package at build time without
leaving any imports in place.
*/
import { version as backendCommon } from '../../../../packages/backend-common/package.json';
import { version as backendPluginApi } from '../../../../packages/backend-plugin-api/package.json';
import { version as backendTestUtils } from '../../../../packages/backend-test-utils/package.json';
@@ -45,10 +43,14 @@ import { version as corePluginApi } from '../../../../packages/core-plugin-api/p
import { version as devUtils } from '../../../../packages/dev-utils/package.json';
import { version as testUtils } from '../../../../packages/test-utils/package.json';
import { version as scaffolderNode } from '../../../../plugins/scaffolder-node/package.json';
import { version as authBackend } from '../../../../plugins/auth-backend/package.json';
import { version as authBackendModuleGuestProvider } from '../../../../plugins/auth-backend-module-guest-provider/package.json';
import { version as theme } from '../../../../packages/theme/package.json';
import { version as backendDefaults } from '../../../../packages/backend-defaults/package.json';
export const packageVersions: Record<string, string> = {
'@backstage/backend-common': backendCommon,
'@backstage/backend-defaults': backendDefaults,
'@backstage/backend-plugin-api': backendPluginApi,
'@backstage/backend-test-utils': backendTestUtils,
'@backstage/cli': cli,
@@ -60,6 +62,9 @@ export const packageVersions: Record<string, string> = {
'@backstage/test-utils': testUtils,
'@backstage/theme': theme,
'@backstage/plugin-scaffolder-node': scaffolderNode,
'@backstage/plugin-auth-backend': authBackend,
'@backstage/plugin-auth-backend-module-guest-provider':
authBackendModuleGuestProvider,
};
export function findVersion() {
@@ -1,4 +1,7 @@
import { coreServices, createBackendModule } from '@backstage/backend-plugin-api';
import {
coreServices,
createBackendModule,
} from '@backstage/backend-plugin-api';
export const {{moduleVar}} = createBackendModule({
pluginId: '{{pluginId}}',
@@ -7,7 +10,7 @@ export const {{moduleVar}} = createBackendModule({
reg.registerInit({
deps: { logger: coreServices.logger },
async init({ logger }) {
logger.info('Hello World!')
logger.info('Hello World!');
},
});
},
@@ -7,7 +7,7 @@ _This plugin was created through the Backstage CLI_
## Getting started
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn
start` in the root directory, and then navigating to [/{{id}}](http://localhost:3000/{{id}}).
start` in the root directory, and then navigating to [/{{pluginVar}}/health](http://localhost:7007/api/{{pluginVar}}/health).
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
@@ -0,0 +1,9 @@
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
backend.add(import('../src'));
backend.start();
@@ -29,6 +29,8 @@
},
"dependencies": {
"@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}",
"@backstage/backend-defaults": "{{versionQuery '@backstage/backend-defaults'}}",
"@backstage/backend-plugin-api": "{{versionQuery '@backstage/backend-plugin-api'}}",
"@backstage/config": "{{versionQuery '@backstage/config'}}",
"@types/express": "{{versionQuery '@types/express' '4.17.6'}}",
"express": "{{versionQuery 'express' '4.17.1'}}",
@@ -39,6 +41,8 @@
},
"devDependencies": {
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
"@backstage/plugin-auth-backend": "{{versionQuery '@backstage/plugin-auth-backend'}}",
"@backstage/plugin-auth-backend-module-guest-provider": "{{versionQuery '@backstage/plugin-auth-backend-module-guest-provider'}}",
"@types/supertest": "{{versionQuery '@types/supertest' '2.0.12'}}",
"supertest": "{{versionQuery 'supertest' '6.2.4'}}",
"msw": "{{versionQuery 'msw' '1.0.0'}}"
@@ -1 +0,0 @@
export * from './service/router';
@@ -0,0 +1,2 @@
export * from './service/router';
export { {{pluginVar}} as default } from './plugin';
@@ -0,0 +1,36 @@
import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { createRouter } from './service/router';
/**
* {{pluginVar}} backend plugin
*
* @public
*/
export const {{pluginVar}} = createBackendPlugin({
pluginId: '{{pluginVar}}',
register(env) {
env.registerInit({
deps: {
httpRouter: coreServices.httpRouter,
logger: coreServices.logger,
},
async init({
httpRouter,
logger,
}) {
httpRouter.use(
await createRouter({
logger,
}),
);
httpRouter.addAuthPolicy({
path: '/health',
allow: 'unauthenticated',
});
},
});
},
});
@@ -1,17 +0,0 @@
import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
startStandaloneServer({ port, enableCors, logger }).catch(err => {
logger.error(err);
process.exit(1);
});
process.on('SIGINT', () => {
logger.info('CTRL+C pressed; exiting.');
process.exit(0);
});
@@ -1,10 +1,10 @@
import { errorHandler } from '@backstage/backend-common';
import { LoggerService } from '@backstage/backend-plugin-api';
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
export interface RouterOptions {
logger: Logger;
logger: LoggerService;
}
export async function createRouter(
@@ -19,6 +19,7 @@ export async function createRouter(
logger.info('PONG!');
response.json({ status: 'ok' });
});
router.use(errorHandler());
return router;
}
@@ -1,34 +0,0 @@
import { createServiceBuilder } from '@backstage/backend-common';
import { Server } from 'http';
import { Logger } from 'winston';
import { createRouter } from './router';
export interface ServerOptions {
port: number;
enableCors: boolean;
logger: Logger;
}
export async function startStandaloneServer(
options: ServerOptions,
): Promise<Server> {
const logger = options.logger.child({ service: '{{id}}-backend' });
logger.debug('Starting application server...');
const router = await createRouter({
logger,
});
let service = createServiceBuilder(module)
.setPort(options.port)
.addRouter('/{{id}}', router);
if (options.enableCors) {
service = service.enableCors({ origin: 'http://localhost:3000' });
}
return await service.start().catch(err => {
logger.error(err);
process.exit(1);
});
}
module.hot?.accept();
@@ -10,10 +10,10 @@
* between the frontend and backend plugin packages.
*/
export type CommonType = {
field: string
}
field: string;
};
/**
* Or you might declare some common constants.
*/
export const COMMON_CONSTANT = 1
export const COMMON_CONSTANT = 1;
@@ -7,6 +7,6 @@ createDevApp()
.addPage({
element: <{{ extensionName }} />,
title: 'Root Page',
path: '/{{ id }}'
path: '/{{ id }}',
})
.render();
@@ -6,7 +6,7 @@ import { screen } from '@testing-library/react';
import {
setupRequestMockHandlers,
renderInTestApp,
} from "@backstage/test-utils";
} from '@backstage/test-utils';
describe('ExampleComponent', () => {
const server = setupServer();
@@ -22,6 +22,8 @@ describe('ExampleComponent', () => {
it('should render', async () => {
await renderInTestApp(<ExampleComponent />);
expect(screen.getByText('Welcome to {{ id }}!')).toBeInTheDocument();
expect(
screen.getByText('Welcome to {{ id }}!'),
).toBeInTheDocument();
});
});
@@ -8,7 +8,7 @@ describe('ExampleFetchComponent', () => {
// Wait for the table to render
const table = await screen.findByRole('table');
const nationality = screen.getAllByText("GB")
const nationality = screen.getAllByText('GB')
// Assert that the table contains the expected user data
expect(table).toBeInTheDocument();
expect(screen.getByAltText('Carolyn')).toBeInTheDocument();
@@ -16,4 +16,4 @@ describe('ExampleFetchComponent', () => {
expect(screen.getByText('carolyn.moore@example.com')).toBeInTheDocument();
expect(nationality[0]).toBeInTheDocument();
});
});
});
@@ -1,232 +1,237 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Table, TableColumn, Progress, ResponseErrorPanel } from '@backstage/core-components';
import {
Table,
TableColumn,
Progress,
ResponseErrorPanel,
} from '@backstage/core-components';
import useAsync from 'react-use/lib/useAsync';
export const exampleUsers = {
"results": [
results: [
{
"gender": "female",
"name": {
"title": "Miss",
"first": "Carolyn",
"last": "Moore"
gender: 'female',
name: {
title: 'Miss',
first: 'Carolyn',
last: 'Moore',
},
"email": "carolyn.moore@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Carolyn",
"nat": "GB"
email: 'carolyn.moore@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Carolyn',
nat: 'GB',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Esma",
"last": "Berberoğlu"
gender: 'female',
name: {
title: 'Ms',
first: 'Esma',
last: 'Berberoğlu',
},
"email": "esma.berberoglu@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Esma",
"nat": "TR"
email: 'esma.berberoglu@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Esma',
nat: 'TR',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Isabella",
"last": "Rhodes"
gender: 'female',
name: {
title: 'Ms',
first: 'Isabella',
last: 'Rhodes',
},
"email": "isabella.rhodes@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella",
"nat": "GB"
email: 'isabella.rhodes@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella',
nat: 'GB',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Derrick",
"last": "Carter"
gender: 'male',
name: {
title: 'Mr',
first: 'Derrick',
last: 'Carter',
},
"email": "derrick.carter@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Derrick",
"nat": "IE"
email: 'derrick.carter@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Derrick',
nat: 'IE',
},
{
"gender": "female",
"name": {
"title": "Miss",
"first": "Mattie",
"last": "Lambert"
gender: 'female',
name: {
title: 'Miss',
first: 'Mattie',
last: 'Lambert',
},
"email": "mattie.lambert@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mattie",
"nat": "AU"
email: 'mattie.lambert@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mattie',
nat: 'AU',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Mijat",
"last": "Rakić"
gender: 'male',
name: {
title: 'Mr',
first: 'Mijat',
last: 'Rakić',
},
"email": "mijat.rakic@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mijat",
"nat": "RS"
email: 'mijat.rakic@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mijat',
nat: 'RS',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Javier",
"last": "Reid"
gender: 'male',
name: {
title: 'Mr',
first: 'Javier',
last: 'Reid',
},
"email": "javier.reid@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Javier",
"nat": "US"
email: 'javier.reid@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Javier',
nat: 'US',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Isabella",
"last": "Li"
gender: 'female',
name: {
title: 'Ms',
first: 'Isabella',
last: 'Li',
},
"email": "isabella.li@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella",
"nat": "CA"
email: 'isabella.li@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella',
nat: 'CA',
},
{
"gender": "female",
"name": {
"title": "Mrs",
"first": "Stephanie",
"last": "Garrett"
gender: 'female',
name: {
title: 'Mrs',
first: 'Stephanie',
last: 'Garrett',
},
"email": "stephanie.garrett@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Stephanie",
"nat": "AU"
email: 'stephanie.garrett@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Stephanie',
nat: 'AU',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Antonia",
"last": "Núñez"
gender: 'female',
name: {
title: 'Ms',
first: 'Antonia',
last: 'Núñez',
},
"email": "antonia.nunez@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Antonia",
"nat": "ES"
email: 'antonia.nunez@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Antonia',
nat: 'ES',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Donald",
"last": "Young"
gender: 'male',
name: {
title: 'Mr',
first: 'Donald',
last: 'Young',
},
"email": "donald.young@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Donald",
"nat": "US"
email: 'donald.young@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Donald',
nat: 'US',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Iegor",
"last": "Holodovskiy"
gender: 'male',
name: {
title: 'Mr',
first: 'Iegor',
last: 'Holodovskiy',
},
"email": "iegor.holodovskiy@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Iegor",
"nat": "UA"
email: 'iegor.holodovskiy@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Iegor',
nat: 'UA',
},
{
"gender": "female",
"name": {
"title": "Madame",
"first": "Jessica",
"last": "David"
gender: 'female',
name: {
title: 'Madame',
first: 'Jessica',
last: 'David',
},
"email": "jessica.david@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Jessica",
"nat": "CH"
email: 'jessica.david@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Jessica',
nat: 'CH',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Eve",
"last": "Martinez"
gender: 'female',
name: {
title: 'Ms',
first: 'Eve',
last: 'Martinez',
},
"email": "eve.martinez@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Eve",
"nat": "FR"
email: 'eve.martinez@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Eve',
nat: 'FR',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Caleb",
"last": "Silva"
gender: 'male',
name: {
title: 'Mr',
first: 'Caleb',
last: 'Silva',
},
"email": "caleb.silva@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Caleb",
"nat": "US"
email: 'caleb.silva@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Caleb',
nat: 'US',
},
{
"gender": "female",
"name": {
"title": "Miss",
"first": "Marcia",
"last": "Jenkins"
gender: 'female',
name: {
title: 'Miss',
first: 'Marcia',
last: 'Jenkins',
},
"email": "marcia.jenkins@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Marcia",
"nat": "US"
email: 'marcia.jenkins@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Marcia',
nat: 'US',
},
{
"gender": "female",
"name": {
"title": "Mrs",
"first": "Mackenzie",
"last": "Jones"
gender: 'female',
name: {
title: 'Mrs',
first: 'Mackenzie',
last: 'Jones',
},
"email": "mackenzie.jones@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Mackenzie",
"nat": "NZ"
email: 'mackenzie.jones@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mackenzie',
nat: 'NZ',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Jeremiah",
"last": "Gutierrez"
gender: 'male',
name: {
title: 'Mr',
first: 'Jeremiah',
last: 'Gutierrez',
},
"email": "jeremiah.gutierrez@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Jeremiah",
"nat": "AU"
email: 'jeremiah.gutierrez@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Jeremiah',
nat: 'AU',
},
{
"gender": "female",
"name": {
"title": "Ms",
"first": "Luciara",
"last": "Souza"
gender: 'female',
name: {
title: 'Ms',
first: 'Luciara',
last: 'Souza',
},
"email": "luciara.souza@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Luciara",
"nat": "BR"
email: 'luciara.souza@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Luciara',
nat: 'BR',
},
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Valgi",
"last": "da Cunha"
gender: 'male',
name: {
title: 'Mr',
first: 'Valgi',
last: 'da Cunha',
},
"email": "valgi.dacunha@example.com",
"picture": "https://api.dicebear.com/6.x/open-peeps/svg?seed=Valgi",
"nat": "BR"
}
]
}
email: 'valgi.dacunha@example.com',
picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Valgi',
nat: 'BR',
},
],
};
const useStyles = makeStyles({
avatar: {
@@ -1,4 +1,7 @@
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
import {
createPlugin,
createRoutableExtension,
} from '@backstage/core-plugin-api';
import { rootRouteRef } from './routes';
@@ -5,14 +5,14 @@ import { ExampleComponent } from './ExampleComponent';
describe('ExampleComponent', () => {
it('should render', async () => {
await renderInTestApp(<ExampleComponent />)
await renderInTestApp(<ExampleComponent />);
expect(screen.getByText('Hello World')).toBeInTheDocument();
});
it('should display a custom message', async () => {
await renderInTestApp(<ExampleComponent message={'Hello Example'} />)
await renderInTestApp(<ExampleComponent message="Hello Example" />);
expect(screen.getByText('Hello Example')).toBeInTheDocument();
})
})
});
});
@@ -11,5 +11,5 @@ export function useExample() {
useEffect(() => {
alertApi.post({ message: 'Hello World!' });
}, [alertApi])
}, [alertApi]);
}
@@ -8,5 +8,5 @@
// In this package you might for example export components or hooks
// that are useful to other plugins or modules.
export * from './components'
export * from './hooks'
export * from './components';
export * from './hooks';
+1 -1
View File
@@ -6,7 +6,7 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Backstage is an open platform for building developer portals"
content="Backstage is an open source framework for building developer portals"
/>
<title>Backstage</title>
</head>