@axinom/mosaic-cli 0.14.2-rc.9 → 0.15.0-rc.0
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/package.json +6 -5
- package/src/cli/README.md +60 -0
- package/src/cli/index.ts +47 -0
- package/src/commands/apply-templates/apply-templates.spec.ts +623 -0
- package/src/commands/apply-templates/apply-templates.ts +494 -0
- package/src/commands/apply-templates/bitwarden-vault.ts +130 -0
- package/src/commands/apply-templates/index.ts +1 -0
- package/src/commands/create-extension-config/create-extension-config.ts +92 -0
- package/src/commands/create-extension-config/index.ts +23 -0
- package/src/commands/get-access-token/get-access-token-options.ts +9 -0
- package/src/commands/get-access-token/get-dev-access-token.ts +32 -0
- package/src/commands/get-access-token/index.ts +66 -0
- package/src/commands/graphql-diff.ts +143 -0
- package/src/commands/msg-codegen/codegen.ts +891 -0
- package/src/commands/msg-codegen/index.ts +48 -0
- package/src/commands/msg-codegen/lint.ts +84 -0
- package/src/commands/msg-codegen/message-codegen-options.ts +7 -0
- package/src/commands/msg-diff/asyncapi-override.ts +31 -0
- package/src/commands/msg-diff/git-checkout-tmp.ts +73 -0
- package/src/commands/msg-diff/index.ts +53 -0
- package/src/commands/msg-diff/message-diff-options.ts +7 -0
- package/src/commands/msg-diff/msg-diff.spec.ts +412 -0
- package/src/commands/msg-diff/msg-diff.ts +364 -0
- package/src/commands/msg-diff/test-resources/0/1-asyncapi.yml +38 -0
- package/src/commands/msg-diff/test-resources/0/2-asyncapi.yml +36 -0
- package/src/commands/msg-diff/test-resources/0/command.json +74 -0
- package/src/commands/msg-diff/test-resources/0/event.json +25 -0
- package/src/commands/msg-diff/test-resources/1/1-asyncapi.yml +25 -0
- package/src/commands/msg-diff/test-resources/1/moved-event.json +25 -0
- package/src/commands/msg-diff/test-resources/common.json +20 -0
- package/src/commands/pg-dump/README.md +21 -0
- package/src/commands/pg-dump/generate.ts +146 -0
- package/src/commands/pg-dump/index.ts +39 -0
- package/src/commands/pg-dump/pg-dump-options.ts +6 -0
- package/src/commands/publish-schema-to-db/README.md +130 -0
- package/src/commands/publish-schema-to-db/abstractions/base-smart-tags.ts +6 -0
- package/src/commands/publish-schema-to-db/abstractions/index.ts +5 -0
- package/src/commands/publish-schema-to-db/abstractions/pg-column.ts +31 -0
- package/src/commands/publish-schema-to-db/abstractions/pg-fk-column.ts +6 -0
- package/src/commands/publish-schema-to-db/abstractions/pg-table.ts +55 -0
- package/src/commands/publish-schema-to-db/abstractions/pg-type.ts +8 -0
- package/src/commands/publish-schema-to-db/content-entity-model.ts +93 -0
- package/src/commands/publish-schema-to-db/generate.ts +82 -0
- package/src/commands/publish-schema-to-db/index.ts +49 -0
- package/src/commands/publish-schema-to-db/jest.config.js +9 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.spec.ts +42 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.ts +41 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/index.ts +4 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.spec.ts +47 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.ts +34 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.spec.ts +65 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.ts +62 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.spec.ts +24 -0
- package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.ts +34 -0
- package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.spec.ts +182 -0
- package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.ts +166 -0
- package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.spec.ts +19 -0
- package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.ts +237 -0
- package/src/commands/publish-schema-to-db/pg-models/pgl-utils.spec.ts +19 -0
- package/src/commands/publish-schema-to-db/pg-models/pgl-utils.ts +115 -0
- package/src/commands/publish-schema-to-db/pg-models/tables/content-entity-table.ts +104 -0
- package/src/commands/publish-schema-to-db/pg-models/tables/index.ts +3 -0
- package/src/commands/publish-schema-to-db/pg-models/tables/object-property-table.ts +113 -0
- package/src/commands/publish-schema-to-db/pg-models/tables/relations-table.ts +115 -0
- package/src/commands/publish-schema-to-db/postprocessors/collection-postprocessor.ts +33 -0
- package/src/commands/publish-schema-to-db/postprocessors/content-entity-model-postprocessor.ts +13 -0
- package/src/commands/publish-schema-to-db/postprocessors/episode-postprocessor.ts +37 -0
- package/src/commands/publish-schema-to-db/postprocessors/index.ts +6 -0
- package/src/commands/publish-schema-to-db/postprocessors/movie-postprocessor.ts +30 -0
- package/src/commands/publish-schema-to-db/postprocessors/postprocessing-utils.ts +21 -0
- package/src/commands/publish-schema-to-db/postprocessors/season-postprocessor.ts +37 -0
- package/src/commands/publish-schema-to-db/postprocessors/tvshow-postprocessor.ts +30 -0
- package/src/commands/publish-schema-to-db/publish-schema-to-db-options.ts +15 -0
- package/src/commands/publish-schema-to-db/types/sql-formatter.d.ts +10 -0
- package/src/exports.ts +2 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
import { diff, DiffOutputItem } from '@asyncapi/diff';
|
|
4
|
+
import { AsyncAPIDocument, Channel, parse } from '@asyncapi/parser';
|
|
5
|
+
import { green, red, white } from 'chalk';
|
|
6
|
+
import * as jsonDiff from 'diff';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as jsonSchemaDiff from 'json-schema-diff';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { override } from './asyncapi-override';
|
|
11
|
+
import { GitCheckoutTmp } from './git-checkout-tmp';
|
|
12
|
+
import { MessageDiffOptions as MessageDiffOptions } from './message-diff-options';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Diff results. Each file (asyncapi document or payload) is classified to one of 'skipped', 'same', 'changed' or 'breaking'.
|
|
16
|
+
*/
|
|
17
|
+
interface Results {
|
|
18
|
+
skipped: number;
|
|
19
|
+
same: number;
|
|
20
|
+
changed: number;
|
|
21
|
+
breaking: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Finds AsyncAPI documents found in git, and compares them with the current file system.
|
|
26
|
+
* The following changes are considered breaking:
|
|
27
|
+
* - Removed / renamed asyncapi document
|
|
28
|
+
* - Breaking changes in any asyncapi document
|
|
29
|
+
* - Breaking changes in any message payload
|
|
30
|
+
* Message payloads are referenced through asyncapi channel definitions. It is safe to rename payload files if
|
|
31
|
+
* file references in the asyncapi document are updated accordingly.
|
|
32
|
+
*
|
|
33
|
+
* @param options (object):
|
|
34
|
+
* schemaRoot Path to directory to scan. All files required to parse the schema must be inside this dir
|
|
35
|
+
* & subdirectories. This includes JSON Schema references.
|
|
36
|
+
* filePattern Regular expression that matches suitable input files.
|
|
37
|
+
* excludePattern Regular expression that matches suitable input files.
|
|
38
|
+
* branch Git branch to compare to.
|
|
39
|
+
* verbose Verbose output includes full diff for all files, not only where breaking changes were found.
|
|
40
|
+
*/
|
|
41
|
+
export class MessageDiff {
|
|
42
|
+
private readonly schemaRoot: string;
|
|
43
|
+
private readonly filePattern: RegExp;
|
|
44
|
+
private readonly excludePattern: RegExp | undefined;
|
|
45
|
+
private readonly branch: string;
|
|
46
|
+
private readonly verbose: boolean;
|
|
47
|
+
|
|
48
|
+
public readonly results = {
|
|
49
|
+
skipped: 0,
|
|
50
|
+
same: 0,
|
|
51
|
+
changed: 0,
|
|
52
|
+
breaking: 0,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
constructor(options: MessageDiffOptions) {
|
|
56
|
+
this.schemaRoot = path.resolve(options.inputDir);
|
|
57
|
+
this.branch = options.branch;
|
|
58
|
+
this.verbose = options.verbose;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
this.filePattern = new RegExp(options.filePattern);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(
|
|
64
|
+
`${options.filePattern} is not a valid regular expression.`,
|
|
65
|
+
);
|
|
66
|
+
process.exit(2);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
this.excludePattern =
|
|
70
|
+
options.excludePattern === undefined
|
|
71
|
+
? undefined
|
|
72
|
+
: new RegExp(options.excludePattern);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(
|
|
75
|
+
`${options.excludePattern} is not a valid regular expression.`,
|
|
76
|
+
);
|
|
77
|
+
process.exit(2);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async run(): Promise<void> {
|
|
82
|
+
// checkout branch to temp dir
|
|
83
|
+
const gitTmp = new GitCheckoutTmp();
|
|
84
|
+
gitTmp.checkout(this.schemaRoot, this.branch);
|
|
85
|
+
const rootDir1 = gitTmp.tmpDir;
|
|
86
|
+
const rootDir2 = gitTmp.gitRoot;
|
|
87
|
+
if (rootDir1 === undefined || rootDir2 === undefined) {
|
|
88
|
+
throw `Git checkout failed`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// scan the checked out files
|
|
92
|
+
try {
|
|
93
|
+
const relPath = path.relative(rootDir2, this.schemaRoot);
|
|
94
|
+
await this.walk(
|
|
95
|
+
path.join(rootDir1, relPath),
|
|
96
|
+
path.join(rootDir2, relPath),
|
|
97
|
+
);
|
|
98
|
+
} finally {
|
|
99
|
+
// remove tmp files
|
|
100
|
+
gitTmp.cleanUp();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// check results
|
|
104
|
+
const totalFiles =
|
|
105
|
+
this.results.skipped +
|
|
106
|
+
this.results.same +
|
|
107
|
+
this.results.changed +
|
|
108
|
+
this.results.breaking;
|
|
109
|
+
|
|
110
|
+
if (totalFiles === 0) {
|
|
111
|
+
throw `No files found matching the given arguments`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const color =
|
|
115
|
+
this.results.breaking > 0
|
|
116
|
+
? red
|
|
117
|
+
: this.results.skipped > 0
|
|
118
|
+
? white
|
|
119
|
+
: green;
|
|
120
|
+
console.log(
|
|
121
|
+
color(
|
|
122
|
+
`${totalFiles} file${totalFiles === 1 ? ' was' : 's were'} checked. ${
|
|
123
|
+
this.results.skipped
|
|
124
|
+
} ${this.results.skipped === 1 ? 'was' : 'were'} skipped. ${
|
|
125
|
+
this.results.same
|
|
126
|
+
} ${this.results.same === 1 ? 'is' : 'are'} the same. ${
|
|
127
|
+
this.results.changed
|
|
128
|
+
} ${
|
|
129
|
+
this.results.changed === 1 ? 'has' : 'have'
|
|
130
|
+
} non-breaking changes. ${this.results.breaking} ${
|
|
131
|
+
this.results.breaking === 1 ? 'has' : 'have'
|
|
132
|
+
} breaking changes.`,
|
|
133
|
+
),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (this.results.breaking > 0) {
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Recursively walks a directory comparing matching files to another directory.
|
|
143
|
+
* @param dir1 - Root dir to scan for matching files.
|
|
144
|
+
* @param dir2 - Root dir for comparision.
|
|
145
|
+
*/
|
|
146
|
+
public async walk(dir1: string, dir2: string): Promise<void> {
|
|
147
|
+
const items = await fs.promises.readdir(dir1);
|
|
148
|
+
|
|
149
|
+
const fullPathItems = items.map((i) => path.join(dir1, i));
|
|
150
|
+
const dirs = fullPathItems.filter((i) => fs.statSync(i).isDirectory());
|
|
151
|
+
const files = fullPathItems.filter(
|
|
152
|
+
(i) =>
|
|
153
|
+
fs.statSync(i).isFile() &&
|
|
154
|
+
this.filePattern.test(i) &&
|
|
155
|
+
(!this.excludePattern || !this.excludePattern.test(i)),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if ([...files, ...dirs].length === 0) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (const file1 of files) {
|
|
163
|
+
const file2 = path.join(dir2, path.relative(dir1, file1));
|
|
164
|
+
await this.asyncApiDiff(file1, file2);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const subDir1 of dirs) {
|
|
168
|
+
const subDir2 = path.join(dir2, path.relative(dir1, subDir1));
|
|
169
|
+
await this.walk(subDir1, subDir2);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Full comparison of asyncapi documents. Each channel payload is also compared.
|
|
175
|
+
*/
|
|
176
|
+
private async asyncApiDiff(file1: string, file2: string): Promise<void> {
|
|
177
|
+
console.log(
|
|
178
|
+
`Comparing asyncapi document '${file2}'. Changes from branch '${this.branch}':`,
|
|
179
|
+
);
|
|
180
|
+
let document1: AsyncAPIDocument;
|
|
181
|
+
let document2: AsyncAPIDocument;
|
|
182
|
+
|
|
183
|
+
// load asyncapi document from git
|
|
184
|
+
try {
|
|
185
|
+
const text = fs.readFileSync(file1, 'utf8');
|
|
186
|
+
document1 = await parse(text, { path: file1 });
|
|
187
|
+
} catch (e: any) {
|
|
188
|
+
throw `Error reading ${file1}: ${e}`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// load local asyncapi document
|
|
192
|
+
try {
|
|
193
|
+
if (!fs.existsSync(file2)) {
|
|
194
|
+
console.log(
|
|
195
|
+
red(
|
|
196
|
+
`❌ File not found. This document may have been removed. Assuming this is a breaking change.`,
|
|
197
|
+
),
|
|
198
|
+
);
|
|
199
|
+
this.results.breaking++;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const text = fs.readFileSync(file2, 'utf8');
|
|
203
|
+
document2 = await parse(text, { path: file2 });
|
|
204
|
+
} catch (e: any) {
|
|
205
|
+
throw `Error reading ${file2}: ${e}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// diff document
|
|
209
|
+
const resultKey = await this.documentDiff(document1, document2);
|
|
210
|
+
this.results[resultKey]++;
|
|
211
|
+
|
|
212
|
+
const channels1 = document1.channels();
|
|
213
|
+
const channels2 = document2.channels();
|
|
214
|
+
|
|
215
|
+
// diff payloads for channels which exist in both documents
|
|
216
|
+
// removed / renamed channels are already marked as breaking
|
|
217
|
+
for (const [k, channel1] of Object.entries(channels1)) {
|
|
218
|
+
if (!(k in channels2)) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
console.log(
|
|
222
|
+
`Comparing payload for channel ${k} in document ${file2}. Changes from branch ${this.branch}`,
|
|
223
|
+
);
|
|
224
|
+
const channel2 = channels2[k];
|
|
225
|
+
const resultKey = await this.payloadDiff(channel1, channel2);
|
|
226
|
+
this.results[resultKey]++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Compare asyncapi documents using AsyncAPI Diff: https://github.com/asyncapi/diff
|
|
232
|
+
* Note: non standard rules are defined in file: asyncapi-override.ts
|
|
233
|
+
*/
|
|
234
|
+
public async documentDiff(
|
|
235
|
+
document1: AsyncAPIDocument,
|
|
236
|
+
document2: AsyncAPIDocument,
|
|
237
|
+
): Promise<keyof Results> {
|
|
238
|
+
// generate diff
|
|
239
|
+
// overrides are applied through options here:
|
|
240
|
+
const output = diff(document1.json(), document2.json(), { override });
|
|
241
|
+
const breaking = output.breaking();
|
|
242
|
+
const nonBreaking = output.nonBreaking();
|
|
243
|
+
const unclassified = output.unclassified();
|
|
244
|
+
|
|
245
|
+
// log full results if breaking changes were found or verbose is set
|
|
246
|
+
const itemMsg = (change: string | DiffOutputItem): string =>
|
|
247
|
+
typeof change === 'string' ? change : `${change.action} ${change.path}`;
|
|
248
|
+
|
|
249
|
+
if (this.verbose) {
|
|
250
|
+
for (const item of unclassified) {
|
|
251
|
+
console.log(` ? ${itemMsg(item)}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (breaking.length > 0 || this.verbose) {
|
|
255
|
+
for (const item of nonBreaking) {
|
|
256
|
+
console.log(` ✔ ${itemMsg(item)}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const item of breaking) {
|
|
260
|
+
console.log(` ✖ ${itemMsg(item)}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// log summary
|
|
264
|
+
const color = breaking.length > 0 ? red : green;
|
|
265
|
+
console.log(
|
|
266
|
+
color(
|
|
267
|
+
`${breaking.length > 0 ? '❌ ' : ''}${
|
|
268
|
+
nonBreaking.length
|
|
269
|
+
} non-breaking change${nonBreaking.length === 1 ? '' : 's'}, ${
|
|
270
|
+
breaking.length
|
|
271
|
+
} breaking change${
|
|
272
|
+
breaking.length === 1 ? '' : 's'
|
|
273
|
+
} in asyncapi document`,
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return breaking.length > 0
|
|
278
|
+
? 'breaking'
|
|
279
|
+
: nonBreaking.length > 0
|
|
280
|
+
? 'changed'
|
|
281
|
+
: 'same';
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Compare payload schemas using JsonSchema Diff: https://www.npmjs.com/package/json-schema-diff
|
|
286
|
+
* NOTE: It might be possible to define rules for asyncapi-diff to compare properties in message schemas but
|
|
287
|
+
* it would not have the ability to properly evaluate breaking changes as json-schema-diff does.
|
|
288
|
+
* e.g. adding an existing property to the list of required properties is a breaking change.
|
|
289
|
+
*
|
|
290
|
+
* Only schema version http://json-schema.org/draft-07/schema# is supported.
|
|
291
|
+
* If any other version is used (in local file or git) then the comparison result will be 'skipped'.
|
|
292
|
+
*/
|
|
293
|
+
public async payloadDiff(
|
|
294
|
+
channel1: Channel,
|
|
295
|
+
channel2: Channel,
|
|
296
|
+
): Promise<keyof Results> {
|
|
297
|
+
const getChannelPayload = (channel: Channel): any => {
|
|
298
|
+
const json = channel.json();
|
|
299
|
+
return (json.subscribe ?? json.publish)?.message?.payload;
|
|
300
|
+
};
|
|
301
|
+
const schema1 = getChannelPayload(channel1);
|
|
302
|
+
const schema2 = getChannelPayload(channel2);
|
|
303
|
+
if (schema1 === undefined) {
|
|
304
|
+
throw `Could not find payload schema in ${this.branch}`;
|
|
305
|
+
}
|
|
306
|
+
if (schema2 === undefined) {
|
|
307
|
+
throw `Could not find payload schema`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
let result: jsonSchemaDiff.DiffResult;
|
|
311
|
+
try {
|
|
312
|
+
result = await jsonSchemaDiff.diffSchemas({
|
|
313
|
+
sourceSchema: schema1,
|
|
314
|
+
destinationSchema: schema2,
|
|
315
|
+
});
|
|
316
|
+
} catch (e: any) {
|
|
317
|
+
// Skip if unsupported schema version is used by either payload
|
|
318
|
+
if (
|
|
319
|
+
e instanceof Error &&
|
|
320
|
+
e.message.startsWith('no schema with key or ref')
|
|
321
|
+
) {
|
|
322
|
+
console.log(
|
|
323
|
+
`WARNING: Unsupported JsonSchema version. This payload will be skipped. Both versions of the file must use $schema: "http://json-schema.org/draft-07/schema#".`,
|
|
324
|
+
);
|
|
325
|
+
return 'skipped';
|
|
326
|
+
}
|
|
327
|
+
throw e;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (result.removalsFound || this.verbose) {
|
|
331
|
+
// json-schema-diff does not give a useful report of what are the breaking changes. See:
|
|
332
|
+
// https://bitbucket.org/atlassian/json-schema-diff/issues/6/is-it-supposed-to-report-only-what-has
|
|
333
|
+
// So we display a line-by-line diff of the schemas..its not targeted to what is breaking, but its more useful
|
|
334
|
+
// than just logging both versions in full which is the observed behavior of json-schema-diff.
|
|
335
|
+
const diffResult = jsonDiff.diffJson(schema1, schema2);
|
|
336
|
+
diffResult.forEach((r) => {
|
|
337
|
+
for (const line of r.value.split(/\r?\n/)) {
|
|
338
|
+
// strip blank lines and annotations added by asyncapi parser
|
|
339
|
+
if (!line || line.match(/^\s+"x-parser-schema/)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
console.log(`${r.removed ? ' -' : r.added ? ' +' : ' '} ${line}`);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const color = result.removalsFound ? red : green;
|
|
348
|
+
console.log(
|
|
349
|
+
color(
|
|
350
|
+
result.removalsFound
|
|
351
|
+
? '❌ Breaking changes in payload'
|
|
352
|
+
: result.additionsFound
|
|
353
|
+
? 'No breaking changes in payload'
|
|
354
|
+
: 'No changes in payload',
|
|
355
|
+
),
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
return result.removalsFound
|
|
359
|
+
? 'breaking'
|
|
360
|
+
: result.additionsFound
|
|
361
|
+
? 'changed'
|
|
362
|
+
: 'same';
|
|
363
|
+
}
|
|
364
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
asyncapi: 2.0.0
|
|
2
|
+
info:
|
|
3
|
+
title: Service 1
|
|
4
|
+
version: '1.0.0'
|
|
5
|
+
description: |
|
|
6
|
+
Testing 1
|
|
7
|
+
# AsyncAPI extension, used to define service id. If not defined, as service id will be used info.title in lower-kebab-case
|
|
8
|
+
x-service-id: ax-service-template
|
|
9
|
+
|
|
10
|
+
channels:
|
|
11
|
+
# commands
|
|
12
|
+
'cmd-channel':
|
|
13
|
+
bindings:
|
|
14
|
+
amqp:
|
|
15
|
+
queue:
|
|
16
|
+
name: example_command
|
|
17
|
+
publish:
|
|
18
|
+
message:
|
|
19
|
+
$ref: '#/components/messages/command-ref'
|
|
20
|
+
# events
|
|
21
|
+
'evt-channel':
|
|
22
|
+
bindings:
|
|
23
|
+
amqp:
|
|
24
|
+
queue:
|
|
25
|
+
name: example_event
|
|
26
|
+
publish:
|
|
27
|
+
message:
|
|
28
|
+
$ref: '#/components/messages/event-ref'
|
|
29
|
+
components:
|
|
30
|
+
messages:
|
|
31
|
+
command-ref:
|
|
32
|
+
contentType: application/json
|
|
33
|
+
payload:
|
|
34
|
+
$ref: 'command.json'
|
|
35
|
+
event-ref:
|
|
36
|
+
contentType: application/json
|
|
37
|
+
payload:
|
|
38
|
+
$ref: 'event.json'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
asyncapi: 2.0.0
|
|
2
|
+
info:
|
|
3
|
+
title: Service 2
|
|
4
|
+
version: '1.0.0'
|
|
5
|
+
description: |
|
|
6
|
+
Testing 2
|
|
7
|
+
|
|
8
|
+
channels:
|
|
9
|
+
# commands
|
|
10
|
+
'cmd-channel':
|
|
11
|
+
bindings:
|
|
12
|
+
amqp:
|
|
13
|
+
queue:
|
|
14
|
+
name: example_command
|
|
15
|
+
publish:
|
|
16
|
+
message:
|
|
17
|
+
$ref: '#/components/messages/command-ref'
|
|
18
|
+
# events
|
|
19
|
+
'evt-channel':
|
|
20
|
+
bindings:
|
|
21
|
+
amqp:
|
|
22
|
+
queue:
|
|
23
|
+
name: example_event
|
|
24
|
+
publish:
|
|
25
|
+
message:
|
|
26
|
+
$ref: '#/components/messages/event-ref'
|
|
27
|
+
components:
|
|
28
|
+
messages:
|
|
29
|
+
command-ref:
|
|
30
|
+
contentType: application/json
|
|
31
|
+
payload:
|
|
32
|
+
$ref: 'command.json'
|
|
33
|
+
event-ref:
|
|
34
|
+
contentType: application/json
|
|
35
|
+
payload:
|
|
36
|
+
$ref: 'event.json'
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type":"object",
|
|
4
|
+
"title": "synchronize_claim_definitions_start_command",
|
|
5
|
+
"description": "Synchronize claim definitions start command schema.",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["claim_definition_groups"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"claim_definition_groups": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"description": "An array of claim definition groups to be registered.",
|
|
12
|
+
"items": {
|
|
13
|
+
"$ref": "#/definitions/claim_definition_group",
|
|
14
|
+
"description": "Defines a group of related claim definitions"
|
|
15
|
+
},
|
|
16
|
+
"minItems": 1
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"definitions": {
|
|
20
|
+
"claim_definition_group": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"title": "claim_definition_group",
|
|
23
|
+
"additionalProperties": false,
|
|
24
|
+
"required": [
|
|
25
|
+
"title",
|
|
26
|
+
"selection_mode",
|
|
27
|
+
"claim_definitions"
|
|
28
|
+
],
|
|
29
|
+
"properties": {
|
|
30
|
+
"title": {
|
|
31
|
+
"$ref": "../common.json#/definitions/non_empty_string",
|
|
32
|
+
"description": "Unique claim definition group title."
|
|
33
|
+
},
|
|
34
|
+
"selection_mode": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"title": "claim_selection_mode",
|
|
37
|
+
"description": "Selection options for a claim definition group.",
|
|
38
|
+
"enum": [
|
|
39
|
+
"SINGLE",
|
|
40
|
+
"MULTIPLE"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"claim_definitions": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"description": "An array of claim definitions.",
|
|
46
|
+
"items": {
|
|
47
|
+
"$ref": "#/definitions/claim_definition",
|
|
48
|
+
"description": "Definition of a claim to be included in a claim set."
|
|
49
|
+
},
|
|
50
|
+
"minItems": 1
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"claim_definition": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"title": "claim_definition",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": [
|
|
59
|
+
"claim",
|
|
60
|
+
"title"
|
|
61
|
+
],
|
|
62
|
+
"properties": {
|
|
63
|
+
"claim": {
|
|
64
|
+
"$ref": "../common.json#/definitions/non_empty_string",
|
|
65
|
+
"description": "The claim."
|
|
66
|
+
},
|
|
67
|
+
"title": {
|
|
68
|
+
"$ref": "../common.json#/definitions/non_empty_string",
|
|
69
|
+
"description": "Display name for the claim."
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type":"object",
|
|
4
|
+
"title": "example_post_created_event",
|
|
5
|
+
"description": "New post created event.",
|
|
6
|
+
"properties": {
|
|
7
|
+
"title": {
|
|
8
|
+
"description": "Title of the post.",
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"content": {
|
|
12
|
+
"description": "Post body, actual content.",
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"is_public": {
|
|
16
|
+
"description": "Indicates whether the post is public.",
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": [
|
|
22
|
+
"title",
|
|
23
|
+
"content"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
asyncapi: 2.0.0
|
|
2
|
+
info:
|
|
3
|
+
title: Template Service
|
|
4
|
+
version: '1.0.0'
|
|
5
|
+
description: |
|
|
6
|
+
Template Management
|
|
7
|
+
# AsyncAPI extension, used to define service id. If not defined, as service id will be used info.title in lower-kebab-case
|
|
8
|
+
x-service-id: ax-service-template
|
|
9
|
+
|
|
10
|
+
channels:
|
|
11
|
+
# events
|
|
12
|
+
'evt-channel':
|
|
13
|
+
bindings:
|
|
14
|
+
amqp:
|
|
15
|
+
queue:
|
|
16
|
+
name: example_event
|
|
17
|
+
publish:
|
|
18
|
+
message:
|
|
19
|
+
$ref: '#/components/messages/event-ref'
|
|
20
|
+
components:
|
|
21
|
+
messages:
|
|
22
|
+
event-ref:
|
|
23
|
+
contentType: application/json
|
|
24
|
+
payload:
|
|
25
|
+
$ref: 'moved-event.json'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type":"object",
|
|
4
|
+
"title": "example_post_created_event",
|
|
5
|
+
"description": "New post created event.",
|
|
6
|
+
"properties": {
|
|
7
|
+
"title": {
|
|
8
|
+
"description": "Title of the post.",
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"content": {
|
|
12
|
+
"description": "Post body, actual content.",
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"is_public": {
|
|
16
|
+
"description": "Indicates whether the post is public.",
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": [
|
|
22
|
+
"title",
|
|
23
|
+
"content"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "common",
|
|
4
|
+
"description": "Common definitions.",
|
|
5
|
+
"definitions": {
|
|
6
|
+
"non_empty_string": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"minLength": 1,
|
|
9
|
+
"pattern": "^$|.*\\S.*",
|
|
10
|
+
"description": "The string has a minimum length of one character and it cannot consist of only whitespace characters."
|
|
11
|
+
},
|
|
12
|
+
"non_empty_uuid": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 32,
|
|
15
|
+
"maxLength": 36,
|
|
16
|
+
"format": "uuid",
|
|
17
|
+
"description": "A UUID."
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
Development command to create a database schema dump (using current service
|
|
4
|
+
config) and put it into `src/generated/db/schema.sql` file of the current
|
|
5
|
+
project.
|
|
6
|
+
|
|
7
|
+
Environment variables must be pre-loaded so that a database connection string
|
|
8
|
+
could be constructed.
|
|
9
|
+
|
|
10
|
+
Shadow database is used as a target to provide a clean schema dump. Shadow
|
|
11
|
+
database is re-created on each migration commit, migration uncommit, and
|
|
12
|
+
database reset in development as a testing ground for migrations, so it always
|
|
13
|
+
has up-to-date schema without unexpected changes.
|
|
14
|
+
|
|
15
|
+
Example call with preload can look like this:
|
|
16
|
+
`dotenv -- mosaic pg-dump -c scripts/infra`, where `dotenv` is a cli command to
|
|
17
|
+
load environment variables using `dotenv-cli` npm package. Alternatively,
|
|
18
|
+
`env-cmd` or some other tool can be used instead of `dotenv`
|
|
19
|
+
|
|
20
|
+
Example call without preload can look like this:
|
|
21
|
+
`mosaic pg-dump -c scripts/infra -s postgres://username:password@localhost:5432/database_name`
|