diff --git a/.changeset/hot-mice-cry.md b/.changeset/hot-mice-cry.md new file mode 100644 index 0000000000..e35538d2de --- /dev/null +++ b/.changeset/hot-mice-cry.md @@ -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 diff --git a/packages/cli-node/report.api.md b/packages/cli-node/report.api.md index bec25ea251..0c13469866 100644 --- a/packages/cli-node/report.api.md +++ b/packages/cli-node/report.api.md @@ -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; }; // (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 { collectPackageNames( diff --git a/packages/cli-node/src/monorepo/PackageGraph.ts b/packages/cli-node/src/monorepo/PackageGraph.ts index 1da896a057..2f82af0808 100644 --- a/packages/cli-node/src/monorepo/PackageGraph.ts +++ b/packages/cli-node/src/monorepo/PackageGraph.ts @@ -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; }; exports?: JsonValue; diff --git a/packages/cli-node/src/monorepo/index.ts b/packages/cli-node/src/monorepo/index.ts index fdb8395c16..14630356b9 100644 --- a/packages/cli-node/src/monorepo/index.ts +++ b/packages/cli-node/src/monorepo/index.ts @@ -16,10 +16,12 @@ export { isMonoRepo } from './isMonoRepo'; export { + packageFeatureType, PackageGraph, type PackageGraphNode, type BackstagePackage, type BackstagePackageJson, + type BackstagePackageFeatureType, } from './PackageGraph'; export { Lockfile, diff --git a/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts b/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts index a12a48c523..054e651f0e 100644 --- a/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts +++ b/packages/cli/src/lib/__testUtils__/createFeatureEnvironment.ts @@ -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'; diff --git a/packages/cli/src/lib/packager/productionPack.ts b/packages/cli/src/lib/packager/productionPack.ts index 9736e97b8d..bfbafc9d27 100644 --- a/packages/cli/src/lib/packager/productionPack.ts +++ b/packages/cli/src/lib/packager/productionPack.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; } } diff --git a/packages/cli/src/lib/typeDistProject.test.ts b/packages/cli/src/lib/typeDistProject.test.ts index dfe3e68ec0..6eef53816b 100644 --- a/packages/cli/src/lib/typeDistProject.test.ts +++ b/packages/cli/src/lib/typeDistProject.test.ts @@ -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', () => { diff --git a/packages/cli/src/lib/typeDistProject.ts b/packages/cli/src/lib/typeDistProject.ts index 59dc503f22..77d6f4a836 100644 --- a/packages/cli/src/lib/typeDistProject.ts +++ b/packages/cli/src/lib/typeDistProject.ts @@ -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) ); }