Skip to content

Commit

Permalink
feat(core): added ability to specify dependencies for catalogs (#1033)
Browse files Browse the repository at this point in the history
* feat(core): added ability to specify dependencies for catalogs

* Create big-poets-decide.md

* feat(core): added ability to specify dependencies for catalogs
  • Loading branch information
boyney123 authored Dec 18, 2024
1 parent ad29fcd commit 972478d
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/big-poets-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@eventcatalog/core": minor
---

feat(core): added ability to specify dependencies for catalogs
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ git-push.sh
/playwright-report/
/blob-report/
/playwright/.cache/

src/__tests__/example-catalog-dependencies/dependencies
6 changes: 6 additions & 0 deletions examples/default/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "default-example-catalog",
"version": "0.1.0",
"private": true
}

79 changes: 79 additions & 0 deletions src/__tests__/example-catalog-dependencies/eventcatalog.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import path from 'path';
import url from 'url';

const __dirname = path.dirname(url.fileURLToPath(import.meta.url));

/** @type {import('@eventcatalog/core/bin/eventcatalog.config').Config} */
export default {
title: 'OurLogix',
tagline: 'A comprehensive logistics and shipping management company',
organizationName: 'OurLogix',
homepageLink: 'https://eventcatalog.dev/',
landingPage: '',
editUrl: 'https://github.com/boyney123/eventcatalog-demo/edit/master',
// By default set to false, add true to get urls ending in /
trailingSlash: false,
// Change to make the base url of the site different, by default https://{website}.com/docs,
// changing to /company would be https://{website}.com/company/docs,
base: '/company',
// Customize the logo, add your logo to public/ folder
logo: {
alt: 'EventCatalog Logo',
src: '/logo.png',
text: 'OurLogix',
},
docs: {
sidebar: {
// Should the sub heading be rendered in the docs sidebar?
showPageHeadings: true,
},
},
dependencies: {
events: [
{ id: 'TestingEventOrder', version: '5.0.0' }
],
services: [
{ id: 'TestingServiceOrder', version: '5.0.0' }
],
domains: [
{ id: 'TestingDomainOrder', version: '5.0.0' }
],
commands: [
{ id: 'TestingCommandOrder', version: '5.0.0' }
],
queries: [
{ id: 'TestingQueryOrder', version: '5.0.0' }
]
},
generators: [
[
'@eventcatalog/generator-asyncapi',
{
services: [
{ path: path.join(__dirname, 'asyncapi-files', 'orders-service.yml') },
{ path: path.join(__dirname, 'asyncapi-files', 'order-fulfillment-service.yml') },
{ path: path.join(__dirname, 'asyncapi-files', 'inventory-service.yml') },
],
domain: { id: 'orders', name: 'Orders', version: '0.0.1' },
},
],
[
'@eventcatalog/generator-asyncapi',
{
services: [
{ path: path.join(__dirname, 'asyncapi-files', 'payment-service.yml') },
{ path: path.join(__dirname, 'asyncapi-files', 'fraud-detection-service.yml') },
],
domain: { id: 'payment', name: 'Payment', version: '0.0.1' },
},
],
[
'@eventcatalog/generator-asyncapi',
{
services: [{ path: path.join(__dirname, 'asyncapi-files', 'user-service.yml') }],
domain: { id: 'users', name: 'User', version: '0.0.1' },
debug: true,
},
],
],
};
4 changes: 4 additions & 0 deletions src/__tests__/example-catalog-dependencies/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "my-catalog",
"version": "0.1.0"
}
94 changes: 94 additions & 0 deletions src/__tests__/resolve-catalog-dependencies.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import resolveCatalogDependencies from '../resolve-catalog-dependencies';
import * as path from 'path';
import fs from 'fs/promises';
import { existsSync } from 'fs';
// import * as fs from 'fs-extra';

const TMP_DIRECTORY = path.join(__dirname, 'tmp');
const ASTRO_OUTPUT = path.join(TMP_DIRECTORY);
const ASTRO_CONTENT_DIRECTORY = path.join(TMP_DIRECTORY, 'src', 'content');
// const OUTPUT_EXTERNAL_FILES = path.join(TMP_DIRECTORY, 'catalog-files');
const CATALOG_DIR = path.join(__dirname, 'example-catalog-dependencies');

import { expect, describe, it, beforeAll, afterAll } from 'vitest';

describe('resolve-catalog-dependencies', () => {
beforeAll(async () => {
await fs.mkdir(TMP_DIRECTORY, { recursive: true });
await fs.mkdir(ASTRO_OUTPUT, { recursive: true });
// create src/content inside astro directory
await fs.mkdir(ASTRO_CONTENT_DIRECTORY, { recursive: true });
await fs.writeFile(path.join(ASTRO_CONTENT_DIRECTORY, 'config.ts'), 'export const config = {};');
});

afterAll(async () => {
await fs.rm(TMP_DIRECTORY, { recursive: true });
});

describe('dependencies', () => {
it('if the dependencies are set in the catalog config, it creates a dependencies directory', async () => {
await resolveCatalogDependencies(CATALOG_DIR, ASTRO_OUTPUT);
expect(existsSync(path.join(CATALOG_DIR, 'dependencies'))).toBe(true);
});

describe('events', () => {
it('creates a dependency file for each event', async () => {
const content = await fs.readFile(
path.join(CATALOG_DIR, 'dependencies', 'events', 'TestingEventOrder', 'index.md'),
'utf8'
);
expect(content).toContain('id: TestingEventOrder');
expect(content).toContain('name: TestingEventOrder');
expect(content).toContain('version: 5.0.0');
});
});

describe('services', () => {
it('creates a dependency file for each service', async () => {
const content = await fs.readFile(
path.join(CATALOG_DIR, 'dependencies', 'services', 'TestingServiceOrder', 'index.md'),
'utf8'
);
expect(content).toContain('id: TestingServiceOrder');
expect(content).toContain('name: TestingServiceOrder');
expect(content).toContain('version: 5.0.0');
});
});

describe('domains', () => {
it('creates a dependency file for each domain', async () => {
const content = await fs.readFile(
path.join(CATALOG_DIR, 'dependencies', 'domains', 'TestingDomainOrder', 'index.md'),
'utf8'
);
expect(content).toContain('id: TestingDomainOrder');
expect(content).toContain('name: TestingDomainOrder');
expect(content).toContain('version: 5.0.0');
});
});

describe('commands', () => {
it('creates a dependency file for each command', async () => {
const content = await fs.readFile(
path.join(CATALOG_DIR, 'dependencies', 'commands', 'TestingCommandOrder', 'index.md'),
'utf8'
);
expect(content).toContain('id: TestingCommandOrder');
expect(content).toContain('name: TestingCommandOrder');
expect(content).toContain('version: 5.0.0');
});
});

describe('queries', () => {
it('creates a dependency file for each query', async () => {
const content = await fs.readFile(
path.join(CATALOG_DIR, 'dependencies', 'queries', 'TestingQueryOrder', 'index.md'),
'utf8'
);
expect(content).toContain('id: TestingQueryOrder');
expect(content).toContain('name: TestingQueryOrder');
expect(content).toContain('version: 5.0.0');
});
});
});
});
11 changes: 11 additions & 0 deletions src/eventcatalog.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ type SideBarConfig = {
visible: boolean;
};

type ResourceDependency = {
id: string;
version?: string;
};

export interface Config {
title: string;
tagline: false;
Expand Down Expand Up @@ -31,4 +36,10 @@ export interface Config {
users?: SideBarConfig;
};
};
dependencies?: {
commands?: ResourceDependency[];
events?: ResourceDependency[];
services?: ResourceDependency[];
domains?: ResourceDependency[];
};
}
3 changes: 3 additions & 0 deletions src/eventcatalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import logBuild from './analytics/log-build';
import { VERSION } from './constants';
import { watch } from './watcher';
import { catalogToAstro } from './catalog-to-astro-content-directory';
import resolveCatalogDependencies from './resolve-catalog-dependencies';

const currentDir = path.dirname(fileURLToPath(import.meta.url));

Expand Down Expand Up @@ -78,6 +79,7 @@ program

console.log('EventCatalog is starting at http://localhost:3000/docs');

await resolveCatalogDependencies(dir, core);
await catalogToAstro(dir, core);

let watchUnsub;
Expand Down Expand Up @@ -114,6 +116,7 @@ program

await logBuild(dir);

await resolveCatalogDependencies(dir, core);
await catalogToAstro(dir, core);

execSync(`cross-env PROJECT_DIR='${dir}' CATALOG_DIR='${core}' npx astro build ${command.args.join(' ').trim()}`, {
Expand Down
1 change: 1 addition & 0 deletions src/map-catalog-to-astro.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const COLLECTION_KEYS = [
'queries',
'channels',
'ubiquitousLanguages',
'dependencies',
];

/**
Expand Down
58 changes: 58 additions & 0 deletions src/resolve-catalog-dependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { getEventCatalogConfigFile } from './eventcatalog-config-file-utils';
import path from 'node:path';
import fs from 'node:fs';

// Create a fake file for this dependency in the project directory ()

export default async (catalogDir, core) => {
const catalogConfig = await getEventCatalogConfigFile(catalogDir);

const dependencies = catalogConfig?.dependencies ?? null;

if (!dependencies) {
// No dependencies found in catalog config just skip
return;
}

// empty the dependencies directory if it exists
const dependenciesDir = path.join(catalogDir, 'dependencies');

if (fs.existsSync(dependenciesDir)) {
fs.rmSync(dependenciesDir, { recursive: true, force: true });
}

// Create a "dependencies" directory in the catalogDir
fs.mkdirSync(dependenciesDir, { recursive: true });

const resourceTypes = Object.keys(dependencies);
for (const resourceType of resourceTypes) {
for (const dependency of dependencies[resourceType]) {
const resource = {
id: dependency.id,
version: dependency.version || '1.0.0',
};

const markdown = `---
id: ${resource.id}
name: ${resource.id}
version: ${resource.version}
---
:::warning
You are running EventCatalog with dependencies enabled.
This resource is mocked and is a dependency. This means that the resource is managed and owned by another catalog.
:::
`;

const resourceFile = path.join(dependenciesDir, resourceType, resource.id, `index.md`);
// ensure the directory exists
fs.mkdirSync(path.dirname(resourceFile), { recursive: true });
fs.writeFileSync(resourceFile, markdown);
}
}

return;
};

0 comments on commit 972478d

Please sign in to comment.