Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions packages/@aws-cdk/aws-service-spec/build/full-database.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as path from 'node:path';
import { SpecDatabase } from '@aws-cdk/service-spec-types';
import { DatabaseBuilder, DatabaseBuilderOptions, ReportAudience } from '@aws-cdk/service-spec-importers';
import { patchOobRelationships } from '@aws-cdk/service-spec-importers/src/patches/oob-relationship-patches';
import { SpecDatabase } from '@aws-cdk/service-spec-types';
import { Augmentations } from './augmentations';
import { Scrutinies } from './scrutinies';
import { patchSamTemplateSpec } from './patches/sam-patches';
import { patchCloudFormationRegistry } from './patches/registry-patches';
import { patchOobRelationships } from '@aws-cdk/service-spec-importers/src/patches/oob-relationship-patches';
import { patchSamTemplateSpec } from './patches/sam-patches';
import { Scrutinies } from './scrutinies';

const SOURCES = path.join(__dirname, '../../../../sources');

Expand All @@ -29,7 +29,8 @@ export class FullDatabase extends DatabaseBuilder {
)
.importLogSources(path.join(SOURCES, 'LogSources/log-source-resource.json'))
.importScrutinies()
.importAugmentations();
.importAugmentations()
.importEventBridgeSchema(path.join(SOURCES, 'EventBridgeSchema'));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"$ref": "#/definitions/EventBridgeSchema",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"EventBridgeSchema": {
"additionalProperties": false,
"description": "Root class of an EventBridge Schema",
"properties": {
"SchemaName": {
"type": "string"
},
"Content": {
"$ref": "#/definitions/EventBridgeContent"
},
"Description": {
"type": "string"
}
},
"required": [
"SchemaName",
"Content",
"Description"
],
"type": "object"
},
"EventBridgeContent": {
"additionalProperties": false,
"properties": {
"components": {
"$ref": "#/definitions/EventBridgeComponents"
}
},
"required": [
"components"
],
"type": "object"
},
"EventBridgeComponents": {
"additionalProperties": false,
"properties": {
"schemas": {
"$ref": "#/definitions/EventBridgeSchemas"
}
},
"required": [
"schemas"
],
"type": "object"
},
"EventBridgeSchemas": {
"additionalProperties": false,
"properties": {
"AWSEvent": {
"$ref": "#/definitions/AWSEvent"
}
},
"required": [
"AWSEvent"
],
"type": "object"
},
"AWSEvent": {
"additionalProperties": false,
"properties": {
"x-amazon-events-detail-type": {
"type": "string"
},
"x-amazon-events-source": {
"type": "string"
},
"properties": {
"$ref": "#/definitions/AWSEventProperties"
}
},
"required": [
"x-amazon-events-detail-type",
"x-amazon-events-source",
"properties"
],
"type": "object"
},
"AWSEventProperties": {
"additionalProperties": false,
"properties": {
"detail": {
"type": "object"
}
},
"required": [
"detail"
],
"type": "object"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const AVAILABLE_SOURCES: Record<string, keyof DatabaseBuilder> = {
arnTemplates: 'importArnTemplates',
oobRelationships: 'importOobRelationships',
logSources: 'importLogSources',
eventbridgeschema: 'importEventBridgeSchema',
};

async function main() {
Expand Down
22 changes: 22 additions & 0 deletions packages/@aws-cdk/service-spec-importers/src/db-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { importArnTemplates } from './importers/import-arn-templates';
import { importCannedMetrics } from './importers/import-canned-metrics';
import { importCloudFormationDocumentation } from './importers/import-cloudformation-docs';
import { importCloudFormationRegistryResource } from './importers/import-cloudformation-registry';
import { importEventBridgeSchema } from './importers/import-eventbridge-schema';
import { importGetAttAllowList } from './importers/import-getatt-allowlist';
import { importLogSources } from './importers/import-log-source';
import { importOobRelationships } from './importers/import-oob-relationships';
Expand All @@ -23,6 +24,7 @@ import {
loadSamSpec,
loadOobRelationships,
} from './loaders';
import { loadDefaultEventBridgeSchema } from './loaders/load-eventbridge-schema';
import { JsonLensPatcher } from './patching';
import { ProblemReport, ReportAudience } from './report';

Expand Down Expand Up @@ -217,6 +219,26 @@ export class DatabaseBuilder {
});
}

public importEventBridgeSchema(schemaDirectory: string) {
return this.addSourceImporter(async (db, report) => {
const regions = await loadDefaultEventBridgeSchema(schemaDirectory, {
...this.options,
report,
failureAudience: this.defaultProblemGrouping,
});
for (const region of regions) {
for (const event of region.events) {
importEventBridgeSchema({
db,
event,
report,
region: region.regionName,
});
}
}
});
}

/**
* Look at a load result and report problems
*/
Expand Down
106 changes: 106 additions & 0 deletions packages/@aws-cdk/service-spec-importers/src/db-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ import {
UpdatedService,
UpdatedTypeDefinition,
MapDiff,
Event,
EventTypeDefinition,
EventProperty,
UpdatedEvent,
UpdatedEventTypeDefinition,
UpdatedEventProperty,
} from '@aws-cdk/service-spec-types';
import {
diffByKey,
Expand Down Expand Up @@ -115,6 +121,7 @@ export class DbDiff {
properties: collapseEmptyDiff(diffMap(a.properties, b.properties, (x, y) => this.diffProperty(x, y))),
typeDefinitionDiff: this.diffResourceTypeDefinitions(a, b),
metrics: this.diffResourceMetrics(a, b),
events: this.diffResourceEvents(a, b),
} satisfies AllFieldsGiven<UpdatedResource>);
}

Expand Down Expand Up @@ -177,6 +184,105 @@ export class DbDiff {
} satisfies AllFieldsGiven<UpdatedTypeDefinition>);
}

public diffResourceEvents(a: Resource, b: Resource): UpdatedResource['events'] {
const aEvents = this.db1.follow('resourceHasEvent', a).map((r) => r.entity);
const bEvents = this.db2.follow('resourceHasEvent', b).map((r) => r.entity);

return collapseEmptyDiff(
diffByKey(
aEvents,
bEvents,
(event) => event.name,
(x, y) => this.diffEvent(x, y),
),
);
}

public diffEvent(a: Event, b: Event): UpdatedEvent | undefined {
return collapseUndefined({
name: diffScalar(a, b, 'name'),
description: diffScalar(a, b, 'description'),
source: diffScalar(a, b, 'source'),
detailType: diffScalar(a, b, 'detailType'),
resourcesField: diffField(a, b, 'resourcesField', jsonEq),
rootProperty: diffField(a, b, 'rootProperty', jsonEq),
typeDefinitionDiff: this.diffEventTypeDefinitions(a, b),
} satisfies AllFieldsGiven<UpdatedEvent>);
}

public diffEventTypeDefinitions(a: Event, b: Event): UpdatedEvent['typeDefinitionDiff'] {
const aTypes = this.db1.follow('eventUsesType', a).map((r) => r.entity);
const bTypes = this.db2.follow('eventUsesType', b).map((r) => r.entity);

return collapseEmptyDiff(
diffByKey(
aTypes,
bTypes,
(type) => type.name,
(x, y) => this.diffEventTypeDefinition(x, y),
),
);
}

public diffEventTypeDefinition(
a: EventTypeDefinition,
b: EventTypeDefinition,
): UpdatedEventTypeDefinition | undefined {
return collapseUndefined({
name: diffScalar(a, b, 'name'),
properties: collapseEmptyDiff(diffMap(a.properties, b.properties, (x, y) => this.diffEventProperty(x, y))),
} satisfies AllFieldsGiven<UpdatedEventTypeDefinition>);
}

public diffEventProperty(a: EventProperty, b: EventProperty): UpdatedEventProperty | undefined {
const anyDiffs = collapseUndefined({
required: diffScalar(a, b, 'required', false),
type: diffField(a, b, 'type', (x, y) => this.eqEventPropertyType(x, y)),
} satisfies DontCareAboutTypes<AllFieldsGiven<EventProperty>>);

if (anyDiffs) {
return { old: a, new: b };
}
return undefined;
}

/**
* Compare event property types by stringifying them.
* Event property types reference EventTypeDefinition, not TypeDefinition.
*/
private eqEventPropertyType(a: EventProperty['type'], b: EventProperty['type']): boolean {
return this.stringifyGenericType(a, this.db1) === this.stringifyGenericType(b, this.db2);
}

/**
* Stringify a generic property type for comparison.
*/
private stringifyGenericType(type: EventProperty['type'], db: SpecDatabase): string {
if (type.type === 'string') return 'string';
if (type.type === 'number') return 'number';
if (type.type === 'integer') return 'integer';
if (type.type === 'boolean') return 'boolean';
if (type.type === 'json') return 'json';
if (type.type === 'date-time') return 'date-time';
if (type.type === 'null') return 'null';
if (type.type === 'tag') return 'tag';
if (type.type === 'ref') {
const entity = db.get('eventTypeDefinition', type.reference.$ref);
return `ref:${entity.name}`;
}
if (type.type === 'array') {
return `array<${this.stringifyGenericType(type.element, db)}>`;
}
if (type.type === 'map') {
return `map<${this.stringifyGenericType(type.element, db)}>`;
}
if (type.type === 'union') {
const types = type.types.map((t) => this.stringifyGenericType(t, db)).sort();
return `union<${types.join('|')}>`;
}
return 'unknown';
}

/**
* Tricky -- we have to deep-compare all the type references which will have different ids in
* different databases.
Expand Down
Loading
Loading