Add default feature type information to backstage metadata

Signed-off-by: Harrison Hogg <hhogg@spotify.com>
This commit is contained in:
Harrison Hogg
2025-01-31 14:28:16 +00:00
parent 72f9a9d1ff
commit f54eed0a7a
8 changed files with 61 additions and 20 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/cli-node': patch
'@backstage/cli': patch
---
Fixed an issue where default feature type information wasn't being added to package.json/exports before publishing if exports didn't exist beforehand
+12
View File
@@ -12,6 +12,9 @@ export type BackstagePackage = {
packageJson: BackstagePackageJson;
};
// @public (undocumented)
export type BackstagePackageFeatureType = (typeof packageFeatureType)[number];
// @public
export interface BackstagePackageJson {
// (undocumented)
@@ -22,6 +25,7 @@ export interface BackstagePackageJson {
pluginId?: string | null;
pluginPackage?: string;
pluginPackages?: string[];
features?: Record<string, BackstagePackageFeatureType>;
};
// (undocumented)
bundled?: boolean;
@@ -112,6 +116,14 @@ export type LockfileDiffEntry = {
range: string;
};
// @public
export const packageFeatureType: readonly [
'@backstage/BackendFeature',
'@backstage/BackstagePlugin',
'@backstage/FrontendPlugin',
'@backstage/FrontendModule',
];
// @public
export class PackageGraph extends Map<string, PackageGraphNode> {
collectPackageNames(
@@ -22,6 +22,24 @@ import { GitUtils } from '../git';
import { Lockfile } from './Lockfile';
import { JsonValue } from '@backstage/types';
/**
* A list of the feature types we want to extract from the project
* and include in the metadata
*
* @public
*/
export const packageFeatureType = [
'@backstage/BackendFeature',
'@backstage/BackstagePlugin',
'@backstage/FrontendPlugin',
'@backstage/FrontendModule',
] as const;
/**
* @public
*/
export type BackstagePackageFeatureType = (typeof packageFeatureType)[number];
/**
* Known fields in Backstage package.json files.
*
@@ -72,6 +90,11 @@ export interface BackstagePackageJson {
* All packages that are part of the plugin. Must always and only be set for plugin packages and plugin library packages.
*/
pluginPackages?: string[];
/**
* The feature types exported from the package, indexed by path.
*/
features?: Record<string, BackstagePackageFeatureType>;
};
exports?: JsonValue;
+2
View File
@@ -16,10 +16,12 @@
export { isMonoRepo } from './isMonoRepo';
export {
packageFeatureType,
PackageGraph,
type PackageGraphNode,
type BackstagePackage,
type BackstagePackageJson,
type BackstagePackageFeatureType,
} from './PackageGraph';
export {
Lockfile,
@@ -14,9 +14,8 @@
* limitations under the License.
*/
import { PackageRole } from '@backstage/cli-node';
import { PackageRole, BackstagePackageFeatureType } from '@backstage/cli-node';
import { Project } from 'ts-morph';
import { BackstagePackageFeatureType } from '../typeDistProject';
const mockEntryPoint = 'dist/index.d.ts';
@@ -188,7 +188,16 @@ async function rewriteEntryPoints(
// This ensures that the `backstage` field is at the top of the
// `exports` field in the package.json because order is important.
// https://nodejs.org/docs/latest-v20.x/api/packages.html#conditional-exports
//
// Adding this to the `exports` field in the package.json is to temporarily
// support any existing behavior that relies on this, however not all packages
// have exports field in their package.json.
exp = { backstage: defaultFeatureType, ...exp };
// Add the default feature type to the backstage metadata in the package.json
pkg.backstage = pkg.backstage ?? {};
pkg.backstage.features = pkg.backstage.features ?? {};
pkg.backstage.features[entryPoint.mount] = defaultFeatureType;
}
}
+2 -5
View File
@@ -14,12 +14,9 @@
* limitations under the License.
*/
import { PackageRole } from '@backstage/cli-node';
import { PackageRole, BackstagePackageFeatureType } from '@backstage/cli-node';
import createFeatureEnvironment from './__testUtils__/createFeatureEnvironment';
import {
getEntryPointDefaultFeatureType,
BackstagePackageFeatureType,
} from './typeDistProject';
import { getEntryPointDefaultFeatureType } from './typeDistProject';
describe('typeDistProject', () => {
describe('for package role', () => {
+6 -13
View File
@@ -13,7 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PackageRole } from '@backstage/cli-node';
import {
BackstagePackageFeatureType,
packageFeatureType,
PackageRole,
} from '@backstage/cli-node';
import { resolve as resolvePath } from 'path';
import { Project, SourceFile, SyntaxKind, ts, Type } from 'ts-morph';
import { paths } from './paths';
@@ -35,17 +39,6 @@ const targetPackageRoles: PackageRole[] = [
'node-library',
];
// A list of the feature types we want to extract from the project
// and include in the metadata
const targetFeatureTypes = [
'@backstage/BackendFeature',
'@backstage/BackstagePlugin',
'@backstage/FrontendPlugin',
'@backstage/FrontendModule',
] as const;
export type BackstagePackageFeatureType = (typeof targetFeatureTypes)[number];
export const getEntryPointDefaultFeatureType = (
role: PackageRole,
packageDir: string,
@@ -146,6 +139,6 @@ function isTargetFeatureType(
type: string | BackstagePackageFeatureType,
): type is BackstagePackageFeatureType {
return (
!!type && targetFeatureTypes.includes(type as BackstagePackageFeatureType)
!!type && packageFeatureType.includes(type as BackstagePackageFeatureType)
);
}