Add integrationFor validation to repo fix command

- Added integrationFor field to BackstagePackageJson type
- Created fixIntegrationFor validator that ensures:
  - Field is only used on module packages
  - Value is an array of strings
  - All entries are valid package names
- Added validator to the publish fixers list

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2026-01-29 20:47:41 +01:00
parent a0ef83cd09
commit 7bd7ed5b31
2 changed files with 54 additions and 0 deletions
@@ -91,6 +91,11 @@ export interface BackstagePackageJson {
*/
pluginPackages?: string[];
/**
* Package names that this module provides integration for. When any of these packages are used, this module should be suggested as a related integration.
*/
integrationFor?: string[];
/**
* The feature types exported from the package, indexed by path.
*/
@@ -430,6 +430,54 @@ export function fixPluginPackages(
}
}
export function fixIntegrationFor(pkg: FixablePackage) {
const pkgBackstage = pkg.packageJson.backstage;
const role = pkgBackstage?.role;
if (!role) {
return;
}
const integrationFor = pkgBackstage.integrationFor;
if (integrationFor === undefined) {
return;
}
// Validate that integrationFor is only used on module packages
if (role !== 'backend-plugin-module' && role !== 'frontend-plugin-module') {
const path = relativePath(
paths.targetRoot,
resolvePath(pkg.dir, 'package.json'),
);
throw new Error(
`The 'backstage.integrationFor' field in "${pkg.packageJson.name}" can only be used on module packages (backend-plugin-module or frontend-plugin-module), but package has role '${role}' in "${path}"`,
);
}
// Validate that integrationFor is an array
if (!Array.isArray(integrationFor)) {
const path = relativePath(
paths.targetRoot,
resolvePath(pkg.dir, 'package.json'),
);
throw new Error(
`Invalid 'backstage.integrationFor' field in "${pkg.packageJson.name}", must be an array of package names in "${path}"`,
);
}
// Validate that all entries are non-empty strings
for (const entry of integrationFor) {
if (typeof entry !== 'string' || entry.length === 0) {
const path = relativePath(
paths.targetRoot,
resolvePath(pkg.dir, 'package.json'),
);
throw new Error(
`Invalid entry in 'backstage.integrationFor' field in "${pkg.packageJson.name}", all entries must be non-empty package name strings in "${path}"`,
);
}
}
}
type PackageFixer = (pkg: FixablePackage, packages: FixablePackage[]) => void;
export async function command(opts: OptionValues): Promise<void> {
@@ -444,6 +492,7 @@ export async function command(opts: OptionValues): Promise<void> {
fixRepositoryField,
fixPluginId,
fixPluginPackages,
fixIntegrationFor,
// Run the publish preflight check too, to make sure we don't uncover errors during publishing
publishPreflightCheck,
);