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

Commit 6085f46

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

File tree

4 files changed

+126
-49
lines changed

4 files changed

+126
-49
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@types/js-yaml": "^4.0.9",
2222
"@types/lodash": "^4.17.7",
2323
"@types/node": "^20.16.1",
24+
"@types/semver": "^7.5.8",
2425
"prettier": "^3.3.3",
2526
"tsup": "^8.1.0",
2627
"typescript": "^5.5.3",
@@ -36,10 +37,11 @@
3637
"dependencies": {
3738
"@apidevtools/swagger-parser": "^10.1.0",
3839
"@changesets/cli": "^2.27.7",
39-
"@eventcatalog/sdk": "^0.1.4",
40+
"@eventcatalog/sdk": "^1.1.2",
4041
"chalk": "^4",
4142
"js-yaml": "^4.1.0",
4243
"openapi-types": "^12.1.3",
44+
"semver": "^7.6.3",
4345
"slugify": "^1.6.6"
4446
}
4547
}

pnpm-lock.yaml

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

src/index.ts

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { getMessageTypeUtils } from './utils/catalog-shorthand';
1212
import { OpenAPI } from 'openapi-types';
1313
import checkLicense from './utils/checkLicense';
1414
import yaml from 'js-yaml';
15+
import * as semver from 'semver';
1516

1617
type Props = {
1718
services: Service[];
@@ -34,6 +35,7 @@ export default async (_: any, options: Props) => {
3435
versionService,
3536
rmServiceById,
3637
writeService,
38+
writeVersionedService,
3739
addFileToService,
3840
getSpecificationFilesForService,
3941
} = utils(process.env.PROJECT_DIR);
@@ -54,9 +56,11 @@ export default async (_: any, options: Props) => {
5456
const version = document.info.version;
5557

5658
const service = buildService(serviceSpec, document);
57-
let serviceMarkdown = service.markdown;
58-
let serviceSpecificationsFiles = [];
59-
let serviceSpecifications = service.specifications;
59+
let isOldVersion = false;
60+
let markdown = service.markdown;
61+
let specFiles = [];
62+
let specifications = service.specifications;
63+
let { sends, receives } = await processMessagesForOpenAPISpec(serviceSpec.path, document);
6064

6165
// Manage domain
6266
if (options.domain) {
@@ -92,64 +96,68 @@ export default async (_: any, options: Props) => {
9296
await addServiceToDomain(domainId, { id: service.id, version: service.version }, domainVersion);
9397
}
9498

95-
// Process all messages for the OpenAPI spec
96-
let { sends, receives } = await processMessagesForOpenAPISpec(serviceSpec.path, document);
97-
9899
// Check if service is already defined... if the versions do not match then create service.
99100
const latestServiceInCatalog = await getService(service.id, 'latest');
101+
const existingVersionInCatalog = await getService(service.id, version);
102+
100103
console.log(chalk.blue(`Processing service: ${document.info.title} (v${version})`));
101104

105+
// Found a service, and versions do not match, we need to version the one already there
102106
if (latestServiceInCatalog) {
103-
serviceMarkdown = latestServiceInCatalog.markdown;
104-
serviceSpecificationsFiles = await getSpecificationFilesForService(service.id, 'latest');
105-
sends = latestServiceInCatalog.sends || ([] as any);
106-
107-
// persist any specifications that are already in the catalog
108-
serviceSpecifications = {
109-
...serviceSpecifications,
110-
...latestServiceInCatalog.specifications,
111-
};
112-
113-
// Found a service, and versions do not match, we need to version the one already there
114-
if (latestServiceInCatalog.version !== version) {
107+
if (isHigherVersion(version, latestServiceInCatalog.version)) {
115108
await versionService(service.id);
116109
console.log(chalk.cyan(` - Versioned previous service (v${latestServiceInCatalog.version})`));
110+
} else {
111+
isOldVersion = true;
112+
console.log(
113+
chalk.yellow(` - Previous Service (v${version}) detected over newer version ${latestServiceInCatalog.version}...`)
114+
);
117115
}
116+
}
117+
118+
if (existingVersionInCatalog) {
119+
markdown = existingVersionInCatalog.markdown;
120+
specFiles = await getSpecificationFilesForService(service.id, version);
121+
sends = existingVersionInCatalog.sends || ([] as any);
122+
receives = [...(existingVersionInCatalog.receives ?? []), ...receives];
123+
124+
// persist any specifications that are already in the catalog
125+
specifications = {
126+
...specifications,
127+
...existingVersionInCatalog.specifications,
128+
};
118129

119130
// Match found, override it
120-
if (latestServiceInCatalog.version === version) {
121-
receives = latestServiceInCatalog.receives ? [...latestServiceInCatalog.receives, ...receives] : receives;
122-
await rmServiceById(service.id);
123-
}
131+
await rmServiceById(service.id, version);
124132
}
125133

126-
await writeService(
134+
const choosenWriteServiceAction = isOldVersion ? writeVersionedService : writeService;
135+
await choosenWriteServiceAction(
127136
{
128137
...service,
129-
markdown: serviceMarkdown,
130-
specifications: serviceSpecifications,
138+
markdown: markdown,
139+
specifications: specifications,
131140
sends,
132141
receives,
133142
},
134-
{ path: service.id }
135143
);
136144

137145
// What files need added to the service (speficiation files)
138-
const specFiles = [
146+
const existingSpecFiles = [
139147
// add any previous spec files to the list
140-
...serviceSpecificationsFiles,
148+
...specFiles,
141149
{
142150
content: saveParsedSpecFile ? getParsedSpecFile(serviceSpec, document) : await getRawSpecFile(serviceSpec),
143151
fileName: service.schemaPath,
144152
},
145153
];
146154

147-
for (const specFile of specFiles) {
155+
for (const spec of existingSpecFiles) {
148156
await addFileToService(
149157
service.id,
150158
{
151-
fileName: specFile.fileName,
152-
content: specFile.content,
159+
fileName: spec.fileName,
160+
content: spec.content,
153161
},
154162
version
155163
);
@@ -243,3 +251,6 @@ const getParsedSpecFile = (service: Service, document: OpenAPI.Document) => {
243251
};
244252

245253
const getRawSpecFile = async (service: Service) => await readFile(service.path, 'utf8');
254+
function isHigherVersion(sourceVersion: string, targetVersion: string) {
255+
return semver.gt(sourceVersion, targetVersion);
256+
}

src/test/plugin.test.ts

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,73 @@ describe('OpenAPI EventCatalog Plugin', () => {
328328
expect(service.specifications?.openapiPath).toEqual('petstore.yml');
329329
});
330330

331+
it('if the service already has higher version the new one with lowert version will be created as versioned', async () => {
332+
const { getService, writeService } = utils(catalogDir);
333+
334+
await writeService(
335+
{
336+
id: 'swagger-petstore',
337+
version: '2.0.0',
338+
name: 'swagger-petstore',
339+
markdown: 'My content',
340+
},
341+
{ path: 'swagger-petstore' }
342+
);
343+
344+
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });
345+
const service = await getService('swagger-petstore', '1.0.0');
346+
const latestservice = await getService('swagger-petstore', '2.0.0');
347+
const serviceMarkdown = (
348+
await fs.readFile(join(catalogDir, 'services', 'swagger-petstore', 'versioned', '1.0.0', 'index.md'), 'utf8')
349+
).toString();
350+
expect(latestservice).toBeDefined();
351+
expect(serviceMarkdown).toBeDefined();
352+
expect(serviceMarkdown).toContain('version: 1.0.0');
353+
354+
});
355+
356+
it('if the service already has higher version the new one with lowert version will be created as versioned', async () => {
357+
const { getService, writeService } = utils(catalogDir);
358+
359+
await writeService(
360+
{
361+
id: 'swagger-petstore',
362+
version: '2.0.0',
363+
name: 'swagger-petstore',
364+
markdown: 'My content',
365+
},
366+
{ path: 'swagger-petstore' }
367+
);
368+
369+
await writeService(
370+
{
371+
id: 'swagger-petstore',
372+
version: '1.0.0',
373+
name: 'swagger-petstore',
374+
markdown: 'My content',
375+
},
376+
{ path: 'swagger-petstore/versioned/1.0.0' }
377+
);
378+
379+
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });
380+
381+
const service = await getService('swagger-petstore', '1.0.0');
382+
const latestservice = await getService('swagger-petstore', '2.0.0');
383+
384+
expect(latestservice).toBeDefined();
385+
expect(service).toBeDefined();
386+
387+
expect(service.receives?.length).toBe(4);
388+
expect(service.markdown).toBe('My content');
389+
});
390+
331391
it('if the service already has specifications they are persisted and the openapi one is added on', async () => {
332392
const { getService, writeService, addFileToService } = utils(catalogDir);
333393

334394
await writeService(
335395
{
336396
id: 'swagger-petstore',
337-
version: '0.0.1',
397+
version: '1.0.0',
338398
name: 'Swagger Petstore',
339399
specifications: {
340400
asyncapiPath: 'asyncapi.yml',
@@ -350,7 +410,7 @@ describe('OpenAPI EventCatalog Plugin', () => {
350410
fileName: 'asyncapi.yml',
351411
content: 'Some content',
352412
},
353-
'0.0.1'
413+
'1.0.0'
354414
);
355415

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

0 commit comments

Comments
 (0)