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

Commit 4133cfa

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

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
@@ -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",
@@ -35,9 +36,10 @@
3536
"dependencies": {
3637
"@apidevtools/swagger-parser": "^10.1.0",
3738
"@changesets/cli": "^2.27.7",
38-
"@eventcatalog/sdk": "^0.1.4",
39+
"@eventcatalog/sdk": "^1.1.2",
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: 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
@@ -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[];
@@ -32,6 +33,7 @@ export default async (_: any, options: Props) => {
3233
versionService,
3334
rmServiceById,
3435
writeService,
36+
writeVersionedService,
3537
addFileToService,
3638
getSpecificationFilesForService,
3739
} = utils(process.env.PROJECT_DIR);
@@ -53,9 +55,11 @@ export default async (_: any, options: Props) => {
5355
const version = document.info.version;
5456

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

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

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

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

118129
// Match found, override it
119-
if (latestServiceInCatalog.version === version) {
120-
receives = latestServiceInCatalog.receives ? [...latestServiceInCatalog.receives, ...receives] : receives;
121-
await rmServiceById(service.id);
122-
}
130+
await rmServiceById(service.id, version);
123131
}
124132

125-
await writeService(
133+
const choosenWriteServiceAction = isOldVersion ? writeVersionedService : writeService;
134+
await choosenWriteServiceAction(
126135
{
127136
...service,
128-
markdown: serviceMarkdown,
129-
specifications: serviceSpecifications,
137+
markdown: markdown,
138+
specifications: specifications,
130139
sends,
131140
receives,
132141
},
133-
{ path: service.id }
134142
);
135143

136144
// What files need added to the service (speficiation files)
137-
const specFiles = [
145+
const existingSpecFiles = [
138146
// add any previous spec files to the list
139-
...serviceSpecificationsFiles,
147+
...specFiles,
140148
{
141149
content: openAPIFile,
142150
fileName: service.schemaPath,
143151
},
144152
];
145153

146-
for (const specFile of specFiles) {
154+
for (const spec of existingSpecFiles) {
147155
await addFileToService(
148156
service.id,
149157
{
150-
fileName: specFile.fileName,
151-
content: specFile.content,
158+
fileName: spec.fileName,
159+
content: spec.content,
152160
},
153161
version
154162
);
@@ -235,3 +243,6 @@ const processMessagesForOpenAPISpec = async (pathToSpec: string, document: OpenA
235243
}
236244
return { receives, sends: [] };
237245
};
246+
function isHigherVersion(sourceVersion: string, targetVersion: string) {
247+
return semver.gt(sourceVersion, targetVersion);
248+
}

src/test/plugin.test.ts

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,73 @@ 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+
const service = await getService('swagger-petstore', '1.0.0');
304+
const latestservice = await getService('swagger-petstore', '2.0.0');
305+
const serviceMarkdown = (
306+
await fs.readFile(join(catalogDir, 'services', 'swagger-petstore', 'versioned', '1.0.0', 'index.md'), 'utf8')
307+
).toString();
308+
expect(latestservice).toBeDefined();
309+
expect(serviceMarkdown).toBeDefined();
310+
expect(serviceMarkdown).toContain('version: 1.0.0');
311+
312+
});
313+
314+
it('if the service already has higher version the new one with lowert version will be created as versioned', async () => {
315+
const { getService, writeService } = utils(catalogDir);
316+
317+
await writeService(
318+
{
319+
id: 'swagger-petstore',
320+
version: '2.0.0',
321+
name: 'swagger-petstore',
322+
markdown: 'My content',
323+
},
324+
{ path: 'swagger-petstore' }
325+
);
326+
327+
await writeService(
328+
{
329+
id: 'swagger-petstore',
330+
version: '1.0.0',
331+
name: 'swagger-petstore',
332+
markdown: 'My content',
333+
},
334+
{ path: 'swagger-petstore/versioned/1.0.0' }
335+
);
336+
337+
await plugin(config, { services: [{ path: join(openAPIExamples, 'petstore.yml'), id: 'swagger-petstore' }] });
338+
339+
const service = await getService('swagger-petstore', '1.0.0');
340+
const latestservice = await getService('swagger-petstore', '2.0.0');
341+
342+
expect(latestservice).toBeDefined();
343+
expect(service).toBeDefined();
344+
345+
expect(service.receives?.length).toBe(4);
346+
expect(service.markdown).toBe('My content');
347+
});
348+
289349
it('if the service already has specifications they are persisted and the openapi one is added on', async () => {
290350
const { getService, writeService, addFileToService } = utils(catalogDir);
291351

292352
await writeService(
293353
{
294354
id: 'swagger-petstore',
295-
version: '0.0.1',
355+
version: '1.0.0',
296356
name: 'Swagger Petstore',
297357
specifications: {
298358
asyncapiPath: 'asyncapi.yml',
@@ -308,7 +368,7 @@ describe('OpenAPI EventCatalog Plugin', () => {
308368
fileName: 'asyncapi.yml',
309369
content: 'Some content',
310370
},
311-
'0.0.1'
371+
'1.0.0'
312372
);
313373

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

0 commit comments

Comments
 (0)