@eventcatalog/cli 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +128 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +128 -13
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli-docs.js +1 -1
- package/dist/cli-docs.js.map +1 -1
- package/dist/cli-docs.mjs +1 -1
- package/dist/cli-docs.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1237,8 +1237,10 @@ import fs from "fs";
|
|
|
1237
1237
|
import path2 from "path";
|
|
1238
1238
|
import yaml from "js-yaml";
|
|
1239
1239
|
var loadGovernanceConfig = (catalogDir) => {
|
|
1240
|
-
const
|
|
1241
|
-
|
|
1240
|
+
const yamlPath = path2.join(catalogDir, "governance.yaml");
|
|
1241
|
+
const ymlPath = path2.join(catalogDir, "governance.yml");
|
|
1242
|
+
const configPath = fs.existsSync(yamlPath) ? yamlPath : fs.existsSync(ymlPath) ? ymlPath : null;
|
|
1243
|
+
if (!configPath) {
|
|
1242
1244
|
return { rules: [] };
|
|
1243
1245
|
}
|
|
1244
1246
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
@@ -1269,17 +1271,82 @@ var buildServiceMessageSets = (snapshot2) => {
|
|
|
1269
1271
|
}
|
|
1270
1272
|
return { produces, consumes };
|
|
1271
1273
|
};
|
|
1272
|
-
var
|
|
1274
|
+
var matchesResourceId = (resourceId, serviceId, resources, messageSets) => {
|
|
1273
1275
|
return resources.some((r) => {
|
|
1274
1276
|
if (r === "*") return true;
|
|
1275
|
-
if (r.startsWith("service:"))
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1277
|
+
if (r.startsWith("service:")) {
|
|
1278
|
+
if (serviceId) return serviceId === r.slice(8);
|
|
1279
|
+
return messageSets?.produces.get(r.slice(8))?.has(resourceId) ?? false;
|
|
1280
|
+
}
|
|
1281
|
+
if (r.startsWith("message:")) return resourceId === r.slice(8);
|
|
1282
|
+
if (r.startsWith("produces:")) return messageSets?.produces.get(r.slice(9))?.has(resourceId) ?? false;
|
|
1283
|
+
if (r.startsWith("consumes:")) return messageSets?.consumes.get(r.slice(9))?.has(resourceId) ?? false;
|
|
1279
1284
|
return false;
|
|
1280
1285
|
});
|
|
1281
1286
|
};
|
|
1282
1287
|
var REMOVED_TRIGGERS = /* @__PURE__ */ new Set(["consumer_removed", "producer_removed"]);
|
|
1288
|
+
var MESSAGE_RESOURCE_TYPES = /* @__PURE__ */ new Set(["event", "command", "query"]);
|
|
1289
|
+
var buildMessageMap = (snapshot2) => {
|
|
1290
|
+
const map = /* @__PURE__ */ new Map();
|
|
1291
|
+
for (const msg of snapshot2.resources.messages.events) map.set(msg.id, msg);
|
|
1292
|
+
for (const msg of snapshot2.resources.messages.commands) map.set(msg.id, msg);
|
|
1293
|
+
for (const msg of snapshot2.resources.messages.queries) map.set(msg.id, msg);
|
|
1294
|
+
return map;
|
|
1295
|
+
};
|
|
1296
|
+
var buildProducerIndex = (snapshot2) => {
|
|
1297
|
+
const index = /* @__PURE__ */ new Map();
|
|
1298
|
+
for (const service of snapshot2.resources.services) {
|
|
1299
|
+
if (!service.sends) continue;
|
|
1300
|
+
for (const s of service.sends) {
|
|
1301
|
+
let producers = index.get(s.id);
|
|
1302
|
+
if (!producers) {
|
|
1303
|
+
producers = [];
|
|
1304
|
+
index.set(s.id, producers);
|
|
1305
|
+
}
|
|
1306
|
+
const entry = {
|
|
1307
|
+
id: service.id,
|
|
1308
|
+
version: service.version
|
|
1309
|
+
};
|
|
1310
|
+
if (service.owners && Array.isArray(service.owners) && service.owners.length > 0) {
|
|
1311
|
+
entry.owners = service.owners;
|
|
1312
|
+
}
|
|
1313
|
+
producers.push(entry);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return index;
|
|
1317
|
+
};
|
|
1318
|
+
var evaluateDeprecationRules = (diff, config, targetSnapshot, targetMessageSets, baseSnapshot) => {
|
|
1319
|
+
const deprecationRules = config.rules.filter((rule) => rule.when.includes("message_deprecated"));
|
|
1320
|
+
if (deprecationRules.length === 0) return [];
|
|
1321
|
+
const targetMessages = buildMessageMap(targetSnapshot);
|
|
1322
|
+
const baseMessages = baseSnapshot ? buildMessageMap(baseSnapshot) : void 0;
|
|
1323
|
+
const producerIndex = buildProducerIndex(targetSnapshot);
|
|
1324
|
+
const deprecatedResources = diff.resources.filter((rc) => {
|
|
1325
|
+
if (!MESSAGE_RESOURCE_TYPES.has(rc.type)) return false;
|
|
1326
|
+
if (!rc.changedFields?.includes("deprecated")) return false;
|
|
1327
|
+
const targetMessage = targetMessages.get(rc.resourceId);
|
|
1328
|
+
if (!targetMessage || !targetMessage.deprecated) return false;
|
|
1329
|
+
if (baseMessages) {
|
|
1330
|
+
const baseMessage = baseMessages.get(rc.resourceId);
|
|
1331
|
+
if (baseMessage && baseMessage.deprecated) return false;
|
|
1332
|
+
}
|
|
1333
|
+
return true;
|
|
1334
|
+
});
|
|
1335
|
+
if (deprecatedResources.length === 0) return [];
|
|
1336
|
+
const results = [];
|
|
1337
|
+
for (const rule of deprecationRules) {
|
|
1338
|
+
const matched = [];
|
|
1339
|
+
for (const rc of deprecatedResources) {
|
|
1340
|
+
if (!matchesResourceId(rc.resourceId, void 0, rule.resources, targetMessageSets)) continue;
|
|
1341
|
+
const producers = producerIndex.get(rc.resourceId) || [];
|
|
1342
|
+
matched.push({ resourceChange: rc, producerServices: producers });
|
|
1343
|
+
}
|
|
1344
|
+
if (matched.length > 0) {
|
|
1345
|
+
results.push({ rule, trigger: "message_deprecated", matchedChanges: [], deprecationChanges: matched });
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
return results;
|
|
1349
|
+
};
|
|
1283
1350
|
var evaluateGovernanceRules = (diff, config, targetSnapshot, baseSnapshot) => {
|
|
1284
1351
|
const results = [];
|
|
1285
1352
|
const targetMessageSets = targetSnapshot ? buildServiceMessageSets(targetSnapshot) : void 0;
|
|
@@ -1289,12 +1356,17 @@ var evaluateGovernanceRules = (diff, config, targetSnapshot, baseSnapshot) => {
|
|
|
1289
1356
|
const filter = TRIGGER_FILTERS[trigger];
|
|
1290
1357
|
if (!filter) continue;
|
|
1291
1358
|
const messageSets = REMOVED_TRIGGERS.has(trigger) && baseMessageSets ? baseMessageSets : targetMessageSets;
|
|
1292
|
-
const matchedChanges = diff.relationships.filter(
|
|
1359
|
+
const matchedChanges = diff.relationships.filter(
|
|
1360
|
+
(c2) => filter(c2) && matchesResourceId(c2.resourceId, c2.serviceId, rule.resources, messageSets)
|
|
1361
|
+
);
|
|
1293
1362
|
if (matchedChanges.length > 0) {
|
|
1294
1363
|
results.push({ rule, trigger, matchedChanges });
|
|
1295
1364
|
}
|
|
1296
1365
|
}
|
|
1297
1366
|
}
|
|
1367
|
+
if (targetSnapshot && targetMessageSets) {
|
|
1368
|
+
results.push(...evaluateDeprecationRules(diff, config, targetSnapshot, targetMessageSets, baseSnapshot));
|
|
1369
|
+
}
|
|
1298
1370
|
return results;
|
|
1299
1371
|
};
|
|
1300
1372
|
var PRODUCER_TRIGGERS = /* @__PURE__ */ new Set(["producer_added", "producer_removed"]);
|
|
@@ -1351,6 +1423,42 @@ var executeGovernanceActions = async (results, opts = {}) => {
|
|
|
1351
1423
|
headers[key] = resolveEnvVars(value);
|
|
1352
1424
|
}
|
|
1353
1425
|
}
|
|
1426
|
+
if (result.deprecationChanges && result.deprecationChanges.length > 0) {
|
|
1427
|
+
for (const dc of result.deprecationChanges) {
|
|
1428
|
+
const messageType = messageTypes?.get(dc.resourceChange.resourceId) || "message";
|
|
1429
|
+
const producers = dc.producerServices.length > 0 ? dc.producerServices : [{ id: "unknown", version: "unknown" }];
|
|
1430
|
+
for (const producer of producers) {
|
|
1431
|
+
const payload = {
|
|
1432
|
+
specversion: "1.0",
|
|
1433
|
+
type: `eventcatalog.governance.message_deprecated`,
|
|
1434
|
+
source: "eventcatalog/governance",
|
|
1435
|
+
id: randomUUID2(),
|
|
1436
|
+
time: now,
|
|
1437
|
+
datacontenttype: "application/json",
|
|
1438
|
+
data: {
|
|
1439
|
+
schemaVersion: 1,
|
|
1440
|
+
...status && { status },
|
|
1441
|
+
summary: `${dc.resourceChange.resourceId} (${messageType}) has been deprecated by ${producer.id}`,
|
|
1442
|
+
producer: {
|
|
1443
|
+
id: producer.id,
|
|
1444
|
+
version: producer.version,
|
|
1445
|
+
...producer.owners && { owners: producer.owners }
|
|
1446
|
+
},
|
|
1447
|
+
message: {
|
|
1448
|
+
id: dc.resourceChange.resourceId,
|
|
1449
|
+
version: dc.resourceChange.version,
|
|
1450
|
+
type: messageType
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
webhookCalls.push({
|
|
1455
|
+
urlTemplate: action.url,
|
|
1456
|
+
request: fetch(url, { method: "POST", headers, body: JSON.stringify(payload) })
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
continue;
|
|
1461
|
+
}
|
|
1354
1462
|
for (const change of result.matchedChanges) {
|
|
1355
1463
|
const verb = getChangeVerb(result.trigger, change.changeType);
|
|
1356
1464
|
const messageType = messageTypes?.get(change.resourceId) || "message";
|
|
@@ -1407,10 +1515,17 @@ var formatGovernanceOutput = (results) => {
|
|
|
1407
1515
|
const lines = ["Governance:", ""];
|
|
1408
1516
|
for (const result of results) {
|
|
1409
1517
|
lines.push(` Rule "${result.rule.name}" triggered (${result.trigger}):`);
|
|
1410
|
-
|
|
1411
|
-
const
|
|
1412
|
-
|
|
1413
|
-
|
|
1518
|
+
if (result.deprecationChanges && result.deprecationChanges.length > 0) {
|
|
1519
|
+
for (const dc of result.deprecationChanges) {
|
|
1520
|
+
const producers = dc.producerServices.length > 0 ? dc.producerServices.map((p) => p.id).join(", ") : "unknown producer";
|
|
1521
|
+
lines.push(` ! ${dc.resourceChange.resourceId} (${dc.resourceChange.type}) deprecated by ${producers}`);
|
|
1522
|
+
}
|
|
1523
|
+
} else {
|
|
1524
|
+
for (const change of result.matchedChanges) {
|
|
1525
|
+
const prefix = change.changeType === "added" ? "+" : "-";
|
|
1526
|
+
const verb = getChangeVerb(result.trigger, change.changeType);
|
|
1527
|
+
lines.push(` ${prefix} ${change.serviceId} is ${verb} ${change.resourceId}`);
|
|
1528
|
+
}
|
|
1414
1529
|
}
|
|
1415
1530
|
lines.push("");
|
|
1416
1531
|
}
|
|
@@ -1471,7 +1586,7 @@ var governanceCheck = async (opts) => {
|
|
|
1471
1586
|
const diff = await baseSDK.diffSnapshots(baseResult.filePath, targetResult.filePath);
|
|
1472
1587
|
const config = loadGovernanceConfig(dir);
|
|
1473
1588
|
if (config.rules.length === 0) {
|
|
1474
|
-
return "No governance.yaml found or no rules defined.";
|
|
1589
|
+
return "No governance.yaml (or governance.yml) found or no rules defined.";
|
|
1475
1590
|
}
|
|
1476
1591
|
const results = evaluateGovernanceRules(diff, config, targetResult.snapshot, baseResult.snapshot);
|
|
1477
1592
|
const messageTypes = buildMessageTypeMap(targetResult.snapshot);
|