fix: omit collecting backend-common package if backend-defaults is included

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-12-20 12:08:32 +01:00
parent 95af0d932a
commit c8d8a1de05
4 changed files with 115 additions and 21 deletions
@@ -93,6 +93,61 @@ describe('collectConfigSchemas', () => {
]);
});
it('should not include schemas for backend-common if theres a backend-defaults package', async () => {
mockDir.setContent({
root: {
'package.json': JSON.stringify({
name: 'root',
configSchema: mockSchema,
dependencies: {},
}),
node_modules: {
a: {
'package.json': JSON.stringify({
name: 'a',
dependencies: {
b: '0.0.0',
},
}),
},
b: {
'package.json': JSON.stringify({
name: 'a',
dependencies: {
b: '0.0.0',
},
}),
},
'@backstage': {
'backend-common': {
'package.json': JSON.stringify({
name: '@backstage/backend-common',
configSchema: { ...mockSchema, title: 'backend-common' },
}),
},
'backend-defaults': {
'package.json': JSON.stringify({
name: '@backstage/backend-defaults',
configSchema: { ...mockSchema, title: 'backend-defaults' },
}),
},
},
},
},
});
process.chdir(mockDir.path);
await expect(
collectConfigSchemas([], [path.join('root', 'package.json')]),
).resolves.toEqual([
{
path: path.join('root', 'package.json'),
value: mockSchema,
},
]);
});
it('should find schema in transitive dependencies and explicit path', async () => {
mockDir.setContent({
root: {
+40 -21
View File
@@ -45,7 +45,7 @@ export async function collectConfigSchemas(
packagePaths: string[],
): Promise<ConfigSchemaPackageEntry[]> {
const schemas = new Array<ConfigSchemaPackageEntry>();
const tsSchemaPaths = new Array<string>();
const tsSchemaPaths = new Array<{ packageName: string; path: string }>();
const visitedPackageVersions = new Map<string, Set<string>>(); // pkgName: [versions...]
const currentDir = await fs.realpath(process.cwd());
@@ -115,22 +115,25 @@ export async function collectConfigSchemas(
);
}
if (isDts) {
tsSchemaPaths.push(
relativePath(
tsSchemaPaths.push({
path: relativePath(
currentDir,
resolvePath(dirname(pkgPath), pkg.configSchema),
),
);
packageName: pkg.name,
});
} else {
const path = resolvePath(dirname(pkgPath), pkg.configSchema);
const value = await fs.readJson(path);
schemas.push({
packageName: pkg.name,
value,
path: relativePath(currentDir, path),
});
}
} else {
schemas.push({
packageName: pkg.name,
value: pkg.configSchema,
path: relativePath(currentDir, pkgPath),
});
@@ -151,14 +154,27 @@ export async function collectConfigSchemas(
const tsSchemas = await compileTsSchemas(tsSchemaPaths);
return schemas.concat(tsSchemas);
return schemas
.concat(tsSchemas)
.filter(
({ packageName }, _, original) =>
true ||
!(
packageName === '@backstage/backend-common' &&
original.some(
({ packageName: p }) => p === '@backstage/backend-defaults',
)
),
);
}
// This handles the support of TypeScript .d.ts config schema declarations.
// We collect all typescript schema definition and compile them all in one go.
// This is much faster than compiling them separately.
async function compileTsSchemas(paths: string[]) {
if (paths.length === 0) {
async function compileTsSchemas(
entries: { path: string; packageName: string }[],
) {
if (entries.length === 0) {
return [];
}
@@ -168,20 +184,23 @@ async function compileTsSchemas(paths: string[]) {
'typescript-json-schema'
);
const program = getProgramFromFiles(paths, {
incremental: false,
isolatedModules: true,
lib: ['ES5'], // Skipping most libs speeds processing up a lot, we just need the primitive types anyway
noEmit: true,
noResolve: true,
skipLibCheck: true, // Skipping lib checks speeds things up
skipDefaultLibCheck: true,
strict: true,
typeRoots: [], // Do not include any additional types
types: [],
});
const program = getProgramFromFiles(
entries.map(({ path }) => path),
{
incremental: false,
isolatedModules: true,
lib: ['ES5'], // Skipping most libs speeds processing up a lot, we just need the primitive types anyway
noEmit: true,
noResolve: true,
skipLibCheck: true, // Skipping lib checks speeds things up
skipDefaultLibCheck: true,
strict: true,
typeRoots: [], // Do not include any additional types
types: [],
},
);
const tsSchemas = paths.map(path => {
const tsSchemas = entries.map(({ path, packageName }) => {
let value;
try {
const generator = buildGenerator(
@@ -228,7 +247,7 @@ async function compileTsSchemas(paths: string[]) {
if (!value) {
throw new Error(`Invalid schema in ${path}, missing Config export`);
}
return { path, value };
return { path, value, packageName };
});
return tsSchemas;
@@ -21,10 +21,12 @@ describe('compileConfigSchemas', () => {
const validate = compileConfigSchemas([
{
path: 'a',
packageName: 'a',
value: { type: 'object', properties: { a: { type: 'string' } } },
},
{
path: 'b',
packageName: 'b',
value: { type: 'object', properties: { b: { type: 'number' } } },
},
]);
@@ -64,6 +66,7 @@ describe('compileConfigSchemas', () => {
const validate = compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -80,6 +83,7 @@ describe('compileConfigSchemas', () => {
},
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
properties: {
@@ -126,6 +130,7 @@ describe('compileConfigSchemas', () => {
compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: { a: { type: 'string', visibility: 'frontend' } },
@@ -133,6 +138,7 @@ describe('compileConfigSchemas', () => {
},
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
properties: { a: { type: 'string', visibility: 'secret' } },
@@ -148,6 +154,7 @@ describe('compileConfigSchemas', () => {
const validate = compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -179,6 +186,7 @@ describe('compileConfigSchemas', () => {
const validate = compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -242,6 +250,7 @@ describe('deepVisibility', () => {
const validate = compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -257,6 +266,7 @@ describe('deepVisibility', () => {
},
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
deepVisibility: 'secret',
@@ -305,6 +315,7 @@ describe('deepVisibility', () => {
compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -320,6 +331,7 @@ describe('deepVisibility', () => {
},
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
deepVisibility: 'secret',
@@ -346,6 +358,7 @@ describe('deepVisibility', () => {
compileConfigSchemas([
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
deepVisibility: 'secret',
@@ -376,6 +389,7 @@ describe('deepVisibility', () => {
compileConfigSchemas([
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
properties: {
@@ -398,6 +412,7 @@ describe('deepVisibility', () => {
compileConfigSchemas([
{
path: 'a1',
packageName: 'a1',
value: {
type: 'object',
properties: {
@@ -418,6 +433,7 @@ describe('deepVisibility', () => {
},
{
path: 'a2',
packageName: 'a2',
value: {
type: 'object',
deepVisibility: 'secret',
@@ -29,6 +29,10 @@ export type ConfigSchemaPackageEntry = {
* The relative path that the configuration schema was discovered at.
*/
path: string;
/**
* The package name for the package this belongs to
*/
packageName: string;
};
/**