@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.
Files changed (41) hide show
  1. package/lib/cli/commands/{config-file/create.d.ts → create.d.ts} +1 -0
  2. package/lib/cli/commands/{mapping-file/create.js → create.js} +20 -4
  3. package/lib/cli/commands/{mapping-file/create.spec.js → create.spec.js} +1 -1
  4. package/lib/cli/commands/upload.d.ts +19 -0
  5. package/lib/cli/commands/upload.js +254 -0
  6. package/lib/cli/commands/upload.spec.js +95 -0
  7. package/lib/cli/index.js +37 -18
  8. package/lib/cli/index.spec.js +53 -111
  9. package/lib/publish/base-process-publish-assortment.d.ts +2 -0
  10. package/lib/publish/base-process-publish-assortment.js +59 -7
  11. package/lib/publish/base-process-publish-assortment.spec.js +188 -0
  12. package/package.json +2 -2
  13. package/scripts/copy-template.js +5 -16
  14. package/lib/cli/commands/config-file/create.js +0 -61
  15. package/lib/cli/commands/config-file/create.spec.js +0 -74
  16. package/lib/cli/commands/config-file/index.d.ts +0 -2
  17. package/lib/cli/commands/config-file/index.js +0 -47
  18. package/lib/cli/commands/config-file/upload.d.ts +0 -8
  19. package/lib/cli/commands/config-file/upload.js +0 -84
  20. package/lib/cli/commands/config-file/upload.spec.js +0 -51
  21. package/lib/cli/commands/mapping-file/create.d.ts +0 -4
  22. package/lib/cli/commands/mapping-file/create.spec.d.ts +0 -1
  23. package/lib/cli/commands/mapping-file/index.d.ts +0 -2
  24. package/lib/cli/commands/mapping-file/index.js +0 -57
  25. package/lib/cli/commands/mapping-file/upload.d.ts +0 -3
  26. package/lib/cli/commands/mapping-file/upload.js +0 -70
  27. package/lib/cli/commands/shared/git.d.ts +0 -6
  28. package/lib/cli/commands/shared/git.js +0 -100
  29. package/lib/cli/commands/shared/prompts.d.ts +0 -2
  30. package/lib/cli/commands/shared/prompts.js +0 -61
  31. package/lib/cli/commands/shared/upload-base.d.ts +0 -24
  32. package/lib/cli/commands/shared/upload-base.js +0 -138
  33. package/lib/cli/commands/shared/upload-base.spec.d.ts +0 -1
  34. package/lib/cli/commands/shared/upload-base.spec.js +0 -99
  35. package/lib/cli/template/config-template.json.template +0 -5
  36. /package/lib/cli/commands/{mapping-file/compile.d.ts → compile.d.ts} +0 -0
  37. /package/lib/cli/commands/{mapping-file/compile.js → compile.js} +0 -0
  38. /package/lib/cli/commands/{mapping-file/compile.spec.d.ts → compile.spec.d.ts} +0 -0
  39. /package/lib/cli/commands/{mapping-file/compile.spec.js → compile.spec.js} +0 -0
  40. /package/lib/cli/commands/{config-file/create.spec.d.ts → create.spec.d.ts} +0 -0
  41. /package/lib/cli/commands/{config-file/upload.spec.d.ts → upload.spec.d.ts} +0 -0
@@ -1,24 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const mappingCreateRun = jest.fn().mockResolvedValue(undefined);
4
- const mappingCompileRun = jest.fn().mockResolvedValue(undefined);
5
- const mappingUploadRun = jest.fn().mockResolvedValue(undefined);
6
- const configCreateRun = jest.fn().mockResolvedValue(undefined);
7
- const configUploadRun = jest.fn().mockResolvedValue(undefined);
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/mapping-file/compile', () => ({
12
- CompileCommand: jest.fn().mockImplementation(() => ({ run: mappingCompileRun })),
9
+ jest.mock('./commands/compile', () => ({
10
+ CompileCommand: jest.fn().mockImplementation(() => ({ run: compileRunMock })),
13
11
  }));
14
- jest.mock('./commands/mapping-file/upload', () => ({
15
- UploadCommand: jest.fn().mockImplementation(() => ({ run: mappingUploadRun })),
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
- mappingCreateRun.mockClear();
32
- mappingCompileRun.mockClear();
33
- mappingUploadRun.mockClear();
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
- describe('mapping-file topic', () => {
52
- it('dispatches mapping-file create', async () => {
53
- setArgv('mapping-file', 'create');
54
- await (0, index_1.main)();
55
- expect(mappingCreateRun).toHaveBeenCalledTimes(1);
56
- expect(mappingCompileRun).not.toHaveBeenCalled();
57
- expect(mappingUploadRun).not.toHaveBeenCalled();
58
- });
59
- it('dispatches mapping-file compile with its argument', async () => {
60
- setArgv('mapping-file', 'compile', 'mapping.ts');
61
- await (0, index_1.main)();
62
- expect(mappingCompileRun).toHaveBeenCalledWith('mapping.ts');
63
- });
64
- it('exits when mapping-file compile is missing its argument', async () => {
65
- setArgv('mapping-file', 'compile');
66
- await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
67
- expect(mappingCompileRun).not.toHaveBeenCalled();
68
- expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
69
- });
70
- it('dispatches mapping-file upload and forwards remaining args', async () => {
71
- setArgv('mapping-file', 'upload', 'mapping.ts', '-m', 'msg', '--skip-git');
72
- await (0, index_1.main)();
73
- expect(mappingUploadRun).toHaveBeenCalledWith(['mapping.ts', '-m', 'msg', '--skip-git']);
74
- });
75
- it('exits when mapping-file upload is missing its argument', async () => {
76
- setArgv('mapping-file', 'upload');
77
- await expect((0, index_1.main)()).rejects.toThrow('__EXIT__:1');
78
- expect(mappingUploadRun).not.toHaveBeenCalled();
79
- expect(errorSpy).toHaveBeenCalledWith(expect.stringMatching(/missing <path\.ts>/));
80
- });
81
- it.each(['help', '-h', '--help'])('prints mapping-file usage on %s', async (helpFlag) => {
82
- setArgv('mapping-file', helpFlag);
83
- await (0, index_1.main)();
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
- describe('config-file topic', () => {
98
- it('dispatches config-file create', async () => {
99
- setArgv('config-file', 'create');
100
- await (0, index_1.main)();
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
- describe('top-level dispatcher', () => {
127
- it.each(['help', '-h', '--help'])('prints top-level usage on %s', async (helpFlag) => {
128
- setArgv(helpFlag);
129
- await (0, index_1.main)();
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 asyncEvent = {
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
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
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 asyncEvent = {
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(asyncEvent));
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 asyncEvent = {
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
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
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
- asyncEvent
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-alpha.71b4d30",
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/**/*",
@@ -2,20 +2,9 @@
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
 
5
- const SRC_DIR = path.join('src', 'cli', 'template');
6
- const DST_DIR = path.join('lib', 'cli', 'template');
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(DST_DIR, { recursive: true });
9
-
10
- const entries = fs.readdirSync(SRC_DIR).filter((name) => name.endsWith('.template'));
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;