@contrail/flexplm 1.7.0-alpha.71b4d30 → 1.7.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/lib/cli/commands/{config-file/create.d.ts → create.d.ts} +1 -0
- package/lib/cli/commands/{mapping-file/create.js → create.js} +20 -4
- package/lib/cli/commands/{mapping-file/create.spec.js → create.spec.js} +1 -1
- package/lib/cli/commands/upload.d.ts +19 -0
- package/lib/cli/commands/upload.js +254 -0
- package/lib/cli/commands/upload.spec.js +95 -0
- package/lib/cli/index.js +37 -18
- package/lib/cli/index.spec.js +53 -111
- package/lib/publish/base-process-publish-assortment.d.ts +2 -0
- package/lib/publish/base-process-publish-assortment.js +59 -7
- package/lib/publish/base-process-publish-assortment.spec.js +188 -0
- package/package.json +2 -2
- package/scripts/copy-template.js +5 -16
- package/lib/cli/commands/config-file/create.js +0 -61
- package/lib/cli/commands/config-file/create.spec.js +0 -74
- package/lib/cli/commands/config-file/index.d.ts +0 -2
- package/lib/cli/commands/config-file/index.js +0 -47
- package/lib/cli/commands/config-file/upload.d.ts +0 -8
- package/lib/cli/commands/config-file/upload.js +0 -84
- package/lib/cli/commands/config-file/upload.spec.js +0 -51
- package/lib/cli/commands/mapping-file/create.d.ts +0 -4
- package/lib/cli/commands/mapping-file/create.spec.d.ts +0 -1
- package/lib/cli/commands/mapping-file/index.d.ts +0 -2
- package/lib/cli/commands/mapping-file/index.js +0 -57
- package/lib/cli/commands/mapping-file/upload.d.ts +0 -3
- package/lib/cli/commands/mapping-file/upload.js +0 -70
- package/lib/cli/commands/shared/git.d.ts +0 -6
- package/lib/cli/commands/shared/git.js +0 -100
- package/lib/cli/commands/shared/prompts.d.ts +0 -2
- package/lib/cli/commands/shared/prompts.js +0 -61
- package/lib/cli/commands/shared/upload-base.d.ts +0 -24
- package/lib/cli/commands/shared/upload-base.js +0 -138
- package/lib/cli/commands/shared/upload-base.spec.d.ts +0 -1
- package/lib/cli/commands/shared/upload-base.spec.js +0 -99
- package/lib/cli/template/config-template.json.template +0 -5
- /package/lib/cli/commands/{mapping-file/compile.d.ts → compile.d.ts} +0 -0
- /package/lib/cli/commands/{mapping-file/compile.js → compile.js} +0 -0
- /package/lib/cli/commands/{mapping-file/compile.spec.d.ts → compile.spec.d.ts} +0 -0
- /package/lib/cli/commands/{mapping-file/compile.spec.js → compile.spec.js} +0 -0
- /package/lib/cli/commands/{config-file/create.spec.d.ts → create.spec.d.ts} +0 -0
- /package/lib/cli/commands/{config-file/upload.spec.d.ts → upload.spec.d.ts} +0 -0
package/lib/cli/index.spec.js
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
jest.mock('./commands/mapping-file/create', () => ({
|
|
9
|
-
CreateCommand: jest.fn().mockImplementation(() => ({ run: mappingCreateRun })),
|
|
3
|
+
const createRunMock = jest.fn().mockResolvedValue(undefined);
|
|
4
|
+
const compileRunMock = jest.fn().mockResolvedValue(undefined);
|
|
5
|
+
const uploadRunMock = jest.fn().mockResolvedValue(undefined);
|
|
6
|
+
jest.mock('./commands/create', () => ({
|
|
7
|
+
CreateCommand: jest.fn().mockImplementation(() => ({ run: createRunMock })),
|
|
10
8
|
}));
|
|
11
|
-
jest.mock('./commands/
|
|
12
|
-
CompileCommand: jest.fn().mockImplementation(() => ({ run:
|
|
9
|
+
jest.mock('./commands/compile', () => ({
|
|
10
|
+
CompileCommand: jest.fn().mockImplementation(() => ({ run: compileRunMock })),
|
|
13
11
|
}));
|
|
14
|
-
jest.mock('./commands/
|
|
15
|
-
UploadCommand: jest.fn().mockImplementation(() => ({ run:
|
|
16
|
-
}));
|
|
17
|
-
jest.mock('./commands/config-file/create', () => ({
|
|
18
|
-
CreateCommand: jest.fn().mockImplementation(() => ({ run: configCreateRun })),
|
|
19
|
-
}));
|
|
20
|
-
jest.mock('./commands/config-file/upload', () => ({
|
|
21
|
-
UploadCommand: jest.fn().mockImplementation(() => ({ run: configUploadRun })),
|
|
12
|
+
jest.mock('./commands/upload', () => ({
|
|
13
|
+
UploadCommand: jest.fn().mockImplementation(() => ({ run: uploadRunMock })),
|
|
22
14
|
}));
|
|
23
15
|
const index_1 = require("./index");
|
|
24
16
|
describe('cli main dispatcher', () => {
|
|
@@ -28,11 +20,9 @@ describe('cli main dispatcher', () => {
|
|
|
28
20
|
let exitSpy;
|
|
29
21
|
beforeEach(() => {
|
|
30
22
|
originalArgv = process.argv;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
configCreateRun.mockClear();
|
|
35
|
-
configUploadRun.mockClear();
|
|
23
|
+
createRunMock.mockClear();
|
|
24
|
+
compileRunMock.mockClear();
|
|
25
|
+
uploadRunMock.mockClear();
|
|
36
26
|
logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
37
27
|
errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
38
28
|
exitSpy = jest.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
@@ -48,96 +38,48 @@ describe('cli main dispatcher', () => {
|
|
|
48
38
|
function setArgv(...args) {
|
|
49
39
|
process.argv = ['node', 'cli', ...args];
|
|
50
40
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm mapping-file/));
|
|
85
|
-
});
|
|
86
|
-
it('prints mapping-file usage when no subcommand is provided', async () => {
|
|
87
|
-
setArgv('mapping-file');
|
|
88
|
-
await (0, index_1.main)();
|
|
89
|
-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm mapping-file/));
|
|
90
|
-
});
|
|
91
|
-
it('exits on an unknown mapping-file subcommand', async () => {
|
|
92
|
-
setArgv('mapping-file', 'bogus');
|
|
93
|
-
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
94
|
-
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown mapping-file subcommand: bogus/));
|
|
95
|
-
});
|
|
41
|
+
it('dispatches the create command', async () => {
|
|
42
|
+
setArgv('create');
|
|
43
|
+
await (0, index_1.main)();
|
|
44
|
+
expect(createRunMock).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(compileRunMock).not.toHaveBeenCalled();
|
|
46
|
+
expect(uploadRunMock).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
it('dispatches the compile command with its argument', async () => {
|
|
49
|
+
setArgv('compile', 'mapping.ts');
|
|
50
|
+
await (0, index_1.main)();
|
|
51
|
+
expect(compileRunMock).toHaveBeenCalledWith('mapping.ts');
|
|
52
|
+
});
|
|
53
|
+
it('exits when compile is missing its argument', async () => {
|
|
54
|
+
setArgv('compile');
|
|
55
|
+
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
56
|
+
expect(compileRunMock).not.toHaveBeenCalled();
|
|
57
|
+
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
|
|
58
|
+
});
|
|
59
|
+
it('dispatches the upload command and forwards remaining args', async () => {
|
|
60
|
+
setArgv('upload', 'mapping.ts', '-m', 'msg', '--skip-git');
|
|
61
|
+
await (0, index_1.main)();
|
|
62
|
+
expect(uploadRunMock).toHaveBeenCalledWith(['mapping.ts', '-m', 'msg', '--skip-git']);
|
|
63
|
+
});
|
|
64
|
+
it('exits when upload is missing its argument', async () => {
|
|
65
|
+
setArgv('upload');
|
|
66
|
+
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
67
|
+
expect(uploadRunMock).not.toHaveBeenCalled();
|
|
68
|
+
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
|
|
69
|
+
});
|
|
70
|
+
it.each(['help', '-h', '--help'])('prints usage for %s', async (helpFlag) => {
|
|
71
|
+
setArgv(helpFlag);
|
|
72
|
+
await (0, index_1.main)();
|
|
73
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-mapping/));
|
|
96
74
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
expect(configCreateRun).toHaveBeenCalledTimes(1);
|
|
102
|
-
expect(configUploadRun).not.toHaveBeenCalled();
|
|
103
|
-
});
|
|
104
|
-
it('dispatches config-file upload and forwards remaining args', async () => {
|
|
105
|
-
setArgv('config-file', 'upload', 'cfg.json', '--update-config', '--skip-git');
|
|
106
|
-
await (0, index_1.main)();
|
|
107
|
-
expect(configUploadRun).toHaveBeenCalledWith(['cfg.json', '--update-config', '--skip-git']);
|
|
108
|
-
});
|
|
109
|
-
it('exits when config-file upload is missing its argument', async () => {
|
|
110
|
-
setArgv('config-file', 'upload');
|
|
111
|
-
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
112
|
-
expect(configUploadRun).not.toHaveBeenCalled();
|
|
113
|
-
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.json>/));
|
|
114
|
-
});
|
|
115
|
-
it('prints config-file usage when no subcommand is provided', async () => {
|
|
116
|
-
setArgv('config-file');
|
|
117
|
-
await (0, index_1.main)();
|
|
118
|
-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm config-file/));
|
|
119
|
-
});
|
|
120
|
-
it('exits on an unknown config-file subcommand', async () => {
|
|
121
|
-
setArgv('config-file', 'bogus');
|
|
122
|
-
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
123
|
-
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown config-file subcommand: bogus/));
|
|
124
|
-
});
|
|
75
|
+
it('prints usage when no command is provided', async () => {
|
|
76
|
+
setArgv();
|
|
77
|
+
await (0, index_1.main)();
|
|
78
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm-mapping/));
|
|
125
79
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm <topic>/));
|
|
131
|
-
});
|
|
132
|
-
it('prints top-level usage when no topic is provided', async () => {
|
|
133
|
-
setArgv();
|
|
134
|
-
await (0, index_1.main)();
|
|
135
|
-
expect(logSpy).toHaveBeenCalledWith(expect.stringMatching(/Usage: flexplm <topic>/));
|
|
136
|
-
});
|
|
137
|
-
it('exits on an unknown topic', async () => {
|
|
138
|
-
setArgv('bogus');
|
|
139
|
-
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
140
|
-
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown topic: bogus/));
|
|
141
|
-
});
|
|
80
|
+
it('exits on an unknown command', async () => {
|
|
81
|
+
setArgv('bogus');
|
|
82
|
+
await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
|
|
83
|
+
expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/Unknown command: bogus/));
|
|
142
84
|
});
|
|
143
85
|
});
|
|
@@ -86,8 +86,10 @@ export declare class BaseProcessPublishAssortment {
|
|
|
86
86
|
getResultsCount(events: any): any;
|
|
87
87
|
private sendEvents;
|
|
88
88
|
private sendToFlexPLM;
|
|
89
|
+
private sendAndRecordPublishEvent;
|
|
89
90
|
private saveToLocalFile;
|
|
90
91
|
private handleVibeIQFile;
|
|
92
|
+
private sendPublishPayloadEvent;
|
|
91
93
|
private getCurrentDateString;
|
|
92
94
|
getItemFamilyChanges(pcd: PublishChangeData, changeDetail: any, assortmentItemFullChangeMap: Map<string, any>, assortmentItemDeleteMap: Map<string, any>): Map<string, ItemFamilyChanges>;
|
|
93
95
|
getEventsForPublishChangeData(publishChangeData: PublishChangeData): Promise<SeasonalPayload[]>;
|
|
@@ -595,14 +595,41 @@ class BaseProcessPublishAssortment {
|
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
597
|
async sendToFlexPLM(events, eventType) {
|
|
598
|
-
const
|
|
598
|
+
const outboundPublishEvent = {
|
|
599
599
|
taskId: this.config.taskId,
|
|
600
600
|
eventType,
|
|
601
601
|
objectClass: 'LCSSeason',
|
|
602
602
|
events
|
|
603
603
|
};
|
|
604
604
|
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
605
|
-
|
|
605
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
606
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
607
|
+
return isResultObject
|
|
608
|
+
? { ...result, outboundPublishEvent }
|
|
609
|
+
: { result, outboundPublishEvent };
|
|
610
|
+
}
|
|
611
|
+
async sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent) {
|
|
612
|
+
let sendResult;
|
|
613
|
+
try {
|
|
614
|
+
sendResult = await flexPLMConnect.sendToFlexPLM(outboundPublishEvent);
|
|
615
|
+
}
|
|
616
|
+
catch (e) {
|
|
617
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
618
|
+
error.outboundPublishEvent = outboundPublishEvent;
|
|
619
|
+
error.sendToFlexPLMResult = { error: e?.message ?? String(e) };
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
624
|
+
}
|
|
625
|
+
catch (e) {
|
|
626
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
627
|
+
error.outboundPublishEvent = outboundPublishEvent;
|
|
628
|
+
error.sendToFlexPLMResult = sendResult;
|
|
629
|
+
error.sendPublishPayloadEventResult = { error: e?.message ?? String(e) };
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
return sendResult;
|
|
606
633
|
}
|
|
607
634
|
async saveToLocalFile(events, eventType) {
|
|
608
635
|
let results = {};
|
|
@@ -614,15 +641,16 @@ class BaseProcessPublishAssortment {
|
|
|
614
641
|
const eventDirName = 'events-output';
|
|
615
642
|
const fileName = `${path.sep}${eventDirName}${path.sep}events-${dateString}.json`;
|
|
616
643
|
fileHandle = await fsPromise.open('.' + fileName, 'a');
|
|
617
|
-
const
|
|
644
|
+
const outboundPublishEvent = {
|
|
618
645
|
taskId: this.config.taskId,
|
|
619
646
|
eventType,
|
|
620
647
|
objectClass: 'LCSSeason',
|
|
621
648
|
events
|
|
622
649
|
};
|
|
623
|
-
await fileHandle.writeFile(JSON.stringify(
|
|
650
|
+
await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
|
|
624
651
|
results = {
|
|
625
652
|
message: 'Successfully Saved File',
|
|
653
|
+
outboundPublishEvent,
|
|
626
654
|
fileLocation: dirName + fileName
|
|
627
655
|
};
|
|
628
656
|
}
|
|
@@ -638,7 +666,7 @@ class BaseProcessPublishAssortment {
|
|
|
638
666
|
const eventBuffer = Buffer.from(JSON.stringify(events), 'utf-8');
|
|
639
667
|
const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
|
|
640
668
|
const uploadFile = await new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
|
|
641
|
-
const
|
|
669
|
+
const outboundPublishEvent = {
|
|
642
670
|
taskId: this.config.taskId,
|
|
643
671
|
eventType,
|
|
644
672
|
objectClass: 'LCSSeason',
|
|
@@ -648,15 +676,39 @@ class BaseProcessPublishAssortment {
|
|
|
648
676
|
};
|
|
649
677
|
if (sendMode === 'vibeiqfile') {
|
|
650
678
|
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
651
|
-
|
|
679
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
680
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
681
|
+
return isResultObject
|
|
682
|
+
? { ...result, outboundPublishEvent }
|
|
683
|
+
: { result, outboundPublishEvent };
|
|
652
684
|
}
|
|
653
685
|
else {
|
|
686
|
+
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
654
687
|
return {
|
|
655
688
|
message: 'Successfully Uploaded File.',
|
|
656
|
-
|
|
689
|
+
outboundPublishEvent
|
|
657
690
|
};
|
|
658
691
|
}
|
|
659
692
|
}
|
|
693
|
+
async sendPublishPayloadEvent(outboundPublishEvent) {
|
|
694
|
+
console.info('sendPublishPayloadEvent()');
|
|
695
|
+
let initialEvent = {};
|
|
696
|
+
if (this.config?.event) {
|
|
697
|
+
initialEvent = (typeof this.config?.event === 'string')
|
|
698
|
+
? JSON.parse(this.config?.event)
|
|
699
|
+
: this.config?.event;
|
|
700
|
+
}
|
|
701
|
+
const eventBody = {
|
|
702
|
+
originSystemType: 'VibeIQ',
|
|
703
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
704
|
+
outboundPublishEvent,
|
|
705
|
+
initialEvent
|
|
706
|
+
};
|
|
707
|
+
await new sdk_1.Entities().create({
|
|
708
|
+
entityName: 'external-event',
|
|
709
|
+
object: eventBody
|
|
710
|
+
});
|
|
711
|
+
}
|
|
660
712
|
getCurrentDateString() {
|
|
661
713
|
const d = new Date();
|
|
662
714
|
return '' + d.getUTCFullYear()
|
|
@@ -9,6 +9,7 @@ const sdk_1 = require("@contrail/sdk");
|
|
|
9
9
|
const type_conversion_utils_1 = require("../util/type-conversion-utils");
|
|
10
10
|
const map_utils_1 = require("../util/map-utils");
|
|
11
11
|
const item_family_changes_1 = require("../interfaces/item-family-changes");
|
|
12
|
+
const flexplm_connect_1 = require("../util/flexplm-connect");
|
|
12
13
|
let federatedId = '';
|
|
13
14
|
jest.mock('../util/data-converter', () => {
|
|
14
15
|
return {
|
|
@@ -31,6 +32,13 @@ jest.mock('../util/federation', () => {
|
|
|
31
32
|
});
|
|
32
33
|
let entityObject = {};
|
|
33
34
|
let getOptionsObject = {};
|
|
35
|
+
let createCallArg = undefined;
|
|
36
|
+
let fileUploadCalls = [];
|
|
37
|
+
let fileUploadResult = {
|
|
38
|
+
id: 'file-123',
|
|
39
|
+
downloadUrl: 'https://download.url',
|
|
40
|
+
adminDownloadUrl: 'https://admin.download.url'
|
|
41
|
+
};
|
|
34
42
|
jest.mock('@contrail/sdk', () => {
|
|
35
43
|
return {
|
|
36
44
|
Entities: class {
|
|
@@ -38,6 +46,18 @@ jest.mock('@contrail/sdk', () => {
|
|
|
38
46
|
getOptionsObject = _getOtionsObject;
|
|
39
47
|
return entityObject;
|
|
40
48
|
}
|
|
49
|
+
create(arg) {
|
|
50
|
+
createCallArg = arg;
|
|
51
|
+
return Promise.resolve({});
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
Files: class {
|
|
55
|
+
createAndUploadFileFromBuffer(buffer, mimeType, fileName, _x, ttl) {
|
|
56
|
+
fileUploadCalls.push({ buffer, mimeType, fileName, ttl });
|
|
57
|
+
return Promise.resolve(fileUploadResult);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
Request: class {
|
|
41
61
|
}
|
|
42
62
|
};
|
|
43
63
|
});
|
|
@@ -1686,3 +1706,171 @@ describe('getEventsForItemFamilyChanges - conditional eventType', () => {
|
|
|
1686
1706
|
expect(type_conversion_utils_1.TypeConversionUtils.isOutboundCreatableFromEntity).toHaveBeenNthCalledWith(2, undefined, mapFileUtil, colorProjectItem, { item: itemData, assortment });
|
|
1687
1707
|
});
|
|
1688
1708
|
});
|
|
1709
|
+
describe('sendToFlexPLM / handleVibeIQFile / sendPublishPayloadEvent', () => {
|
|
1710
|
+
const config = {
|
|
1711
|
+
taskId: 'task-abc',
|
|
1712
|
+
event: '{"sourceEventId":"src-1"}'
|
|
1713
|
+
};
|
|
1714
|
+
const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
|
|
1715
|
+
const dc = new data_converter_1.DataConverter(config, mapFileUtil);
|
|
1716
|
+
const events = [{ objectClass: 'LCSProductSeasonLink' }];
|
|
1717
|
+
const eventType = 'ASYNC_PUBLISH_SEASON';
|
|
1718
|
+
beforeEach(() => {
|
|
1719
|
+
createCallArg = undefined;
|
|
1720
|
+
fileUploadCalls = [];
|
|
1721
|
+
fileUploadResult = {
|
|
1722
|
+
id: 'file-123',
|
|
1723
|
+
downloadUrl: 'https://download.url',
|
|
1724
|
+
adminDownloadUrl: 'https://admin.download.url'
|
|
1725
|
+
};
|
|
1726
|
+
});
|
|
1727
|
+
afterEach(() => {
|
|
1728
|
+
jest.restoreAllMocks();
|
|
1729
|
+
});
|
|
1730
|
+
it('should merge outboundPublishEvent into result and call sendPublishPayloadEvent after sendToFlexPLM succeeds', async () => {
|
|
1731
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1732
|
+
const flexResponse = { status: 200, data: { ok: true } };
|
|
1733
|
+
const callOrder = [];
|
|
1734
|
+
const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
1735
|
+
.mockImplementation(async () => {
|
|
1736
|
+
await new Promise(r => setTimeout(r, 5));
|
|
1737
|
+
callOrder.push('flex');
|
|
1738
|
+
return flexResponse;
|
|
1739
|
+
});
|
|
1740
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
|
|
1741
|
+
.mockImplementation(async () => {
|
|
1742
|
+
callOrder.push('event');
|
|
1743
|
+
});
|
|
1744
|
+
const result = await bppa.sendToFlexPLM(events, eventType);
|
|
1745
|
+
expect(spyFlex).toHaveBeenCalledTimes(1);
|
|
1746
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
1747
|
+
expect(callOrder).toEqual(['flex', 'event']);
|
|
1748
|
+
const passedOutboundPublishEvent = spyFlex.mock.calls[0][0];
|
|
1749
|
+
expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
|
|
1750
|
+
expect(passedOutboundPublishEvent.eventType).toBe(eventType);
|
|
1751
|
+
expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
|
|
1752
|
+
expect(passedOutboundPublishEvent.events).toBe(events);
|
|
1753
|
+
expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
|
|
1754
|
+
expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
|
|
1755
|
+
});
|
|
1756
|
+
it('should have sendToFlexPLM throw when flexPLMConnect.sendToFlexPLM fails, without calling sendPublishPayloadEvent', async () => {
|
|
1757
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1758
|
+
const flexError = new Error('flex failed');
|
|
1759
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1760
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent').mockResolvedValue(undefined);
|
|
1761
|
+
await expect(bppa.sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
1762
|
+
message: 'flex failed',
|
|
1763
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType, objectClass: 'LCSSeason', events }),
|
|
1764
|
+
sendToFlexPLMResult: { error: 'flex failed' }
|
|
1765
|
+
});
|
|
1766
|
+
expect(spyEvent).not.toHaveBeenCalled();
|
|
1767
|
+
expect(flexError.sendPublishPayloadEventResult).toBeUndefined();
|
|
1768
|
+
});
|
|
1769
|
+
it('should have sendToFlexPLM throw when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
1770
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1771
|
+
const flexResponse = { status: 200 };
|
|
1772
|
+
const eventError = new Error('event failed');
|
|
1773
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse);
|
|
1774
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1775
|
+
await expect(bppa.sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
1776
|
+
message: 'event failed',
|
|
1777
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType }),
|
|
1778
|
+
sendToFlexPLMResult: flexResponse,
|
|
1779
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
1780
|
+
});
|
|
1781
|
+
});
|
|
1782
|
+
it('should have handleVibeIQFile (vibeiqfile) throw when flexPLMConnect.sendToFlexPLM fails, without calling sendPublishPayloadEvent', async () => {
|
|
1783
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1784
|
+
const flexError = new Error('flex failed');
|
|
1785
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1786
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent').mockResolvedValue(undefined);
|
|
1787
|
+
await expect(bppa.handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
1788
|
+
message: 'flex failed',
|
|
1789
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
1790
|
+
sendToFlexPLMResult: { error: 'flex failed' }
|
|
1791
|
+
});
|
|
1792
|
+
expect(spyEvent).not.toHaveBeenCalled();
|
|
1793
|
+
expect(flexError.sendPublishPayloadEventResult).toBeUndefined();
|
|
1794
|
+
});
|
|
1795
|
+
it('should have handleVibeIQFile (vibeiqfile) throw when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
1796
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1797
|
+
const flexResponse = { status: 200 };
|
|
1798
|
+
const eventError = new Error('event failed');
|
|
1799
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse);
|
|
1800
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1801
|
+
await expect(bppa.handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
1802
|
+
message: 'event failed',
|
|
1803
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
1804
|
+
sendToFlexPLMResult: flexResponse,
|
|
1805
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
1806
|
+
});
|
|
1807
|
+
});
|
|
1808
|
+
it('should merge outboundPublishEvent into FlexPLM result and call sendPublishPayloadEvent when mode is vibeiqfile', async () => {
|
|
1809
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1810
|
+
const flexResponse = { status: 200, data: { ok: true } };
|
|
1811
|
+
const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
1812
|
+
.mockResolvedValue(flexResponse);
|
|
1813
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
|
|
1814
|
+
.mockResolvedValue(undefined);
|
|
1815
|
+
const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile');
|
|
1816
|
+
expect(fileUploadCalls).toHaveLength(1);
|
|
1817
|
+
expect(fileUploadCalls[0].fileName).toBe('ASYNC_PUBLISH_SEASON-events.json');
|
|
1818
|
+
expect(fileUploadCalls[0].mimeType).toBe('application/json');
|
|
1819
|
+
const passedOutboundPublishEvent = spyFlex.mock.calls[0][0];
|
|
1820
|
+
expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
|
|
1821
|
+
expect(passedOutboundPublishEvent.eventType).toBe(eventType);
|
|
1822
|
+
expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
|
|
1823
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
1824
|
+
expect(passedOutboundPublishEvent.eventsDownloadLink).toBe('https://download.url');
|
|
1825
|
+
expect(passedOutboundPublishEvent.eventsAdminDownloadLink).toBe('https://admin.download.url');
|
|
1826
|
+
expect(spyFlex).toHaveBeenCalledTimes(1);
|
|
1827
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
1828
|
+
expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
|
|
1829
|
+
expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
|
|
1830
|
+
});
|
|
1831
|
+
it('should skip FlexPLM but still call sendPublishPayloadEvent when mode is vibeiqfile-dontsendtoflexplm', async () => {
|
|
1832
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1833
|
+
const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
1834
|
+
.mockResolvedValue({});
|
|
1835
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
|
|
1836
|
+
.mockResolvedValue(undefined);
|
|
1837
|
+
const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile-dontsendtoflexplm');
|
|
1838
|
+
expect(spyFlex).not.toHaveBeenCalled();
|
|
1839
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
1840
|
+
const passedOutboundPublishEvent = spyEvent.mock.calls[0][0];
|
|
1841
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
1842
|
+
expect(result).toEqual({
|
|
1843
|
+
message: 'Successfully Uploaded File.',
|
|
1844
|
+
outboundPublishEvent: passedOutboundPublishEvent
|
|
1845
|
+
});
|
|
1846
|
+
});
|
|
1847
|
+
it('should create an external-event with initialEvent parsed from config', async () => {
|
|
1848
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1849
|
+
const outboundPublishEvent = { foo: 'bar' };
|
|
1850
|
+
await bppa.sendPublishPayloadEvent(outboundPublishEvent);
|
|
1851
|
+
expect(createCallArg).toEqual({
|
|
1852
|
+
entityName: 'external-event',
|
|
1853
|
+
object: {
|
|
1854
|
+
originSystemType: 'VibeIQ',
|
|
1855
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
1856
|
+
outboundPublishEvent,
|
|
1857
|
+
initialEvent: { sourceEventId: 'src-1' }
|
|
1858
|
+
}
|
|
1859
|
+
});
|
|
1860
|
+
});
|
|
1861
|
+
it('should default initialEvent to {} when config has no event', async () => {
|
|
1862
|
+
const bareConfig = { taskId: 'task-x' };
|
|
1863
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(bareConfig, dc, mapFileUtil);
|
|
1864
|
+
const outboundPublishEvent = { hello: 'world' };
|
|
1865
|
+
await bppa.sendPublishPayloadEvent(outboundPublishEvent);
|
|
1866
|
+
expect(createCallArg).toEqual({
|
|
1867
|
+
entityName: 'external-event',
|
|
1868
|
+
object: {
|
|
1869
|
+
originSystemType: 'VibeIQ',
|
|
1870
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
1871
|
+
outboundPublishEvent,
|
|
1872
|
+
initialEvent: {}
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
});
|
|
1876
|
+
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrail/flexplm",
|
|
3
|
-
"version": "1.7.0
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Library used for integration with flexplm.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"flexplm": "lib/cli/index.js"
|
|
8
|
+
"flexplm-mapping": "lib/cli/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"lib/**/*",
|
package/scripts/copy-template.js
CHANGED
|
@@ -2,20 +2,9 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const SRC = path.join('src', 'cli', 'template', 'mapping-template.ts.template');
|
|
6
|
+
const DST = path.join('lib', 'cli', 'template', 'mapping-template.ts.template');
|
|
7
7
|
|
|
8
|
-
fs.mkdirSync(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (entries.length === 0) {
|
|
12
|
-
console.warn(`No .template files found in ${SRC_DIR}`);
|
|
13
|
-
process.exit(0);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
for (const name of entries) {
|
|
17
|
-
const src = path.join(SRC_DIR, name);
|
|
18
|
-
const dst = path.join(DST_DIR, name);
|
|
19
|
-
fs.copyFileSync(src, dst);
|
|
20
|
-
console.log(`Copied ${src} -> ${dst}`);
|
|
21
|
-
}
|
|
8
|
+
fs.mkdirSync(path.dirname(DST), { recursive: true });
|
|
9
|
+
fs.copyFileSync(SRC, DST);
|
|
10
|
+
console.log(`Copied ${SRC} -> ${DST}`);
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.CreateCommand = void 0;
|
|
27
|
-
const fs = __importStar(require("fs"));
|
|
28
|
-
const path = __importStar(require("path"));
|
|
29
|
-
const prompts_1 = require("../shared/prompts");
|
|
30
|
-
const TEMPLATE_FILENAME = 'config-template.json.template';
|
|
31
|
-
const PLACEHOLDER = '<ORG_NAME>';
|
|
32
|
-
class CreateCommand {
|
|
33
|
-
findTemplate() {
|
|
34
|
-
const candidates = [
|
|
35
|
-
path.join(__dirname, '..', '..', 'template', TEMPLATE_FILENAME),
|
|
36
|
-
path.join(__dirname, '..', '..', '..', '..', 'src', 'cli', 'template', TEMPLATE_FILENAME),
|
|
37
|
-
];
|
|
38
|
-
for (const candidate of candidates) {
|
|
39
|
-
if (fs.existsSync(candidate)) {
|
|
40
|
-
return candidate;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
throw new Error(`Could not locate ${TEMPLATE_FILENAME}. Tried:\n ${candidates.join('\n ')}`);
|
|
44
|
-
}
|
|
45
|
-
async run() {
|
|
46
|
-
const orgName = (await (0, prompts_1.prompt)('orgName: ')).trim();
|
|
47
|
-
if (!orgName) {
|
|
48
|
-
throw new Error('orgName is required');
|
|
49
|
-
}
|
|
50
|
-
const templatePath = this.findTemplate();
|
|
51
|
-
const templateBody = fs.readFileSync(templatePath, 'utf8');
|
|
52
|
-
const rendered = templateBody.split(PLACEHOLDER).join(orgName);
|
|
53
|
-
const outPath = path.resolve(process.cwd(), `${orgName}-config.json`);
|
|
54
|
-
if (fs.existsSync(outPath)) {
|
|
55
|
-
throw new Error(`Refusing to overwrite existing file: ${outPath}`);
|
|
56
|
-
}
|
|
57
|
-
fs.writeFileSync(outPath, rendered, 'utf8');
|
|
58
|
-
console.log(`Created ${outPath}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
exports.CreateCommand = CreateCommand;
|