Skip to content
This repository was archived by the owner on Feb 5, 2025. It is now read-only.

Commit 1ffa5ee

Browse files
committed
feat([openapi]): if service version is lower than latest add a service version in versioned folder
1 parent 867add3 commit 1ffa5ee

File tree

4 files changed

+105
-32
lines changed

4 files changed

+105
-32
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@types/fs-extra": "^11.0.4",
2121
"@types/lodash": "^4.17.7",
2222
"@types/node": "^20.16.1",
23+
"@types/semver": "^7.5.8",
2324
"prettier": "^3.3.3",
2425
"tsup": "^8.1.0",
2526
"typescript": "^5.5.3",
@@ -38,6 +39,7 @@
3839
"@eventcatalog/sdk": "^0.1.4",
3940
"chalk": "^4",
4041
"openapi-types": "^12.1.3",
42+
"semver": "^7.6.3",
4143
"slugify": "^1.6.6"
4244
}
4345
}

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Domain, Service } from './types';
1111
import { getMessageTypeUtils } from './utils/catalog-shorthand';
1212
import { OpenAPI } from 'openapi-types';
1313
import checkLicense from './utils/checkLicense';
14+
import * as semver from 'semver';
1415

1516
type Props = {
1617
services: Service[];
@@ -50,6 +51,7 @@ export default async (_: any, options: Props) => {
5051

5152
const services = options.services ?? [];
5253
validateOptions(options);
54+
5355
for (const serviceSpec of services) {
5456
console.log(chalk.green(`Processing ${serviceSpec.path}`));
5557

@@ -66,9 +68,11 @@ export default async (_: any, options: Props) => {
6668
const version = document.info.version;
6769

6870
const service = buildService(serviceSpec, document);
69-
let serviceMarkdown = service.markdown;
70-
let serviceSpecificationsFiles = [];
71-
let serviceSpecifications = service.specifications;
71+
let serviceCatalogPath = service.id;
72+
let markdown = service.markdown;
73+
let specFiles = [];
74+
let specifications = service.specifications;
75+
let { sends, receives } = await processMessagesForOpenAPISpec(serviceSpec.path, document);
7276

7377
// Manage domain
7478
if (options.domain) {
@@ -104,64 +108,66 @@ export default async (_: any, options: Props) => {
104108
await addServiceToDomain(domainId, { id: service.id, version: service.version }, domainVersion);
105109
}
106110

107-
// Process all messages for the OpenAPI spec
108-
let { sends, receives } = await processMessagesForOpenAPISpec(serviceSpec.path, document);
109-
110111
// Check if service is already defined... if the versions do not match then create service.
111112
const latestServiceInCatalog = await getService(service.id, 'latest');
113+
const existingVersionInCatalog = await getService(service.id, version);
114+
112115
console.log(chalk.blue(`Processing service: ${document.info.title} (v${version})`));
113116

117+
// Found a service, and versions do not match, we need to version the one already there
114118
if (latestServiceInCatalog) {
115-
serviceMarkdown = latestServiceInCatalog.markdown;
116-
serviceSpecificationsFiles = await getSpecificationFilesForService(service.id, 'latest');
117-
sends = latestServiceInCatalog.sends || ([] as any);
118-
119-
// persist any specifications that are already in the catalog
120-
serviceSpecifications = {
121-
...serviceSpecifications,
122-
...latestServiceInCatalog.specifications,
123-
};
124-
125-
// Found a service, and versions do not match, we need to version the one already there
126-
if (latestServiceInCatalog.version !== version) {
119+
if (isHigherVersion(version, latestServiceInCatalog.version)) {
127120
await versionService(service.id);
128121
console.log(chalk.cyan(` - Versioned previous service (v${latestServiceInCatalog.version})`));
122+
} else {
123+
serviceCatalogPath = serviceCatalogPath.concat(`/versioned/${version}`);
124+
console.log(chalk.yellow(` - Service (v${latestServiceInCatalog.version}) already exists, skipped creation...`));
129125
}
126+
}
127+
128+
if (existingVersionInCatalog) {
129+
markdown = existingVersionInCatalog.markdown;
130+
specFiles = await getSpecificationFilesForService(service.id, version);
131+
sends = existingVersionInCatalog.sends || ([] as any);
132+
receives = [...(existingVersionInCatalog.receives ?? []), ...receives];
133+
134+
// persist any specifications that are already in the catalog
135+
specifications = {
136+
...specifications,
137+
...existingVersionInCatalog.specifications,
138+
};
130139

131140
// Match found, override it
132-
if (latestServiceInCatalog.version === version) {
133-
receives = latestServiceInCatalog.receives ? [...latestServiceInCatalog.receives, ...receives] : receives;
134-
await rmServiceById(service.id);
135-
}
141+
await rmServiceById(service.id, version);
136142
}
137143

138144
await writeService(
139145
{
140146
...service,
141-
markdown: serviceMarkdown,
142-
specifications: serviceSpecifications,
147+
markdown: markdown,
148+
specifications: specifications,
143149
sends,
144150
receives,
145151
},
146-
{ path: service.id }
152+
{ path: serviceCatalogPath }
147153
);
148154

149155
// What files need added to the service (speficiation files)
150-
const specFiles = [
156+
const existingSpecFiles = [
151157
// add any previous spec files to the list
152-
...serviceSpecificationsFiles,
158+
...specFiles,
153159
{
154160
content: openAPIFile,
155161
fileName: service.schemaPath,
156162
},
157163
];
158164

159-
for (const specFile of specFiles) {
165+
for (const spec of existingSpecFiles) {
160166
await addFileToService(
161167
service.id,
162168
{
163-
fileName: specFile.fileName,
164-
content: specFile.content,
169+
fileName: spec.fileName,
170+
content: spec.content,
165171
},
166172
version
167173
);
@@ -248,3 +254,6 @@ const processMessagesForOpenAPISpec = async (pathToSpec: string, document: OpenA
248254
}
249255
return { receives, sends: [] };
250256
};
257+
function isHigherVersion(sourceVersion: string, targetVersion: string) {
258+
return semver.gt(sourceVersion, targetVersion);
259+
}

src/test/plugin.test.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,69 @@ describe('OpenAPI EventCatalog Plugin', () => {
286286
expect(service.specifications?.openapiPath).toEqual('petstore.yml');
287287
});
288288

289+
it('if the service already has higher version the new one with lowert version will be created as versioned', async () => {
290+
const { getService, writeService } = utils(catalogDir);
291+
292+
await writeService(
293+
{
294+
id: 'swagger-petstore',
295+
version: '2.0.0',
296+
name: 'swagger-petstore',
297+
markdown: 'My content',
298+
},
299+
{ path: 'swagger-petstore' }
300+
);
301+
302+
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });
303+
304+
const service = await getService('swagger-petstore', '1.0.0');
305+
const latestservice = await getService('swagger-petstore', '2.0.0');
306+
expect(service).toBeDefined();
307+
expect(latestservice).toBeDefined();
308+
});
309+
310+
it('if the service already has higher version the new one with lowert version will be created as versioned', async () => {
311+
const { getService, writeService } = utils(catalogDir);
312+
313+
await writeService(
314+
{
315+
id: 'swagger-petstore',
316+
version: '2.0.0',
317+
name: 'swagger-petstore',
318+
markdown: 'My content',
319+
},
320+
{ path: 'swagger-petstore' }
321+
);
322+
323+
await writeService(
324+
{
325+
id: 'swagger-petstore',
326+
version: '1.0.0',
327+
name: 'swagger-petstore',
328+
markdown: 'My content',
329+
},
330+
{ path: 'swagger-petstore/versioned/1.0.0' }
331+
);
332+
333+
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });
334+
335+
const service = await getService('swagger-petstore', '1.0.0');
336+
const latestservice = await getService('swagger-petstore', '2.0.0');
337+
338+
expect(latestservice).toBeDefined();
339+
expect(service).toBeDefined();
340+
341+
expect(service.receives?.length).toBe(4);
342+
expect(service.markdown).toBe('My content');
343+
});
344+
289345
it('if the service already has specifications they are persisted and the openapi one is added on', async () => {
290346
const { getService, writeService, addFileToService } = utils(catalogDir);
291347

292348
await writeService(
293349
{
294350
id: 'swagger-petstore',
295-
version: '0.0.1',
351+
version: '1.0.0',
296352
name: 'Swagger Petstore',
297353
specifications: {
298354
asyncapiPath: 'asyncapi.yml',
@@ -308,7 +364,7 @@ describe('OpenAPI EventCatalog Plugin', () => {
308364
fileName: 'asyncapi.yml',
309365
content: 'Some content',
310366
},
311-
'0.0.1'
367+
'1.0.0'
312368
);
313369

314370
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });

0 commit comments

Comments
 (0)