diff --git a/docs/user-guide/config-commands.md b/docs/user-guide/config-commands.md index 4f2c1381..a9893d72 100644 --- a/docs/user-guide/config-commands.md +++ b/docs/user-guide/config-commands.md @@ -382,6 +382,12 @@ The params argument should be passed in a key value format separated by commas w --params key1=value1,key2=value2,...,keyN=valueN ``` +Supported types are `DATA_MODEL`, `CONNECTION` and `DATA_POOL_ID`. Each returns a list of assignments: + +```json +[{"value": "4b4f32c8-4529-43f1-9399-2a6de94ac13a", "name": "Order Management Pool"}] +``` + ### Mapping Variables After getting the variables list (with definitions and assignments in the source team) and the assignments (possible values on the target team), you can change the value of the source team to one of the options provided when listing assignments. diff --git a/src/commands/configuration-management/api/variable-assignment-candidates-api.ts b/src/commands/configuration-management/api/variable-assignment-candidates-api.ts index 921e2c52..3d45fc37 100644 --- a/src/commands/configuration-management/api/variable-assignment-candidates-api.ts +++ b/src/commands/configuration-management/api/variable-assignment-candidates-api.ts @@ -1,5 +1,5 @@ import {URLSearchParams} from "url"; -import { variableAssignmentApis } from "../interfaces/variable-assignment-apis.constants"; +import { VariableAssignment, variableAssignmentApis } from "../interfaces/variable-assignment-apis.constants"; import { HttpClient } from "../../../core/http/http-client"; import { Context } from "../../../core/command/cli-context"; import { FatalError } from "../../../core/utils/logger"; @@ -12,15 +12,20 @@ export class VariableAssignmentCandidatesApi { this.httpClient = () => context.httpClient; } - public async getCandidateAssignments(type: string, params: URLSearchParams): Promise { - if (!variableAssignmentApis[type]) { + public async getCandidateAssignments(type: string, params: URLSearchParams): Promise { + const assignmentApi = variableAssignmentApis[type]; + if (!assignmentApi) { throw new FatalError(`Variable type ${type} not supported.`); } - const apiUrl: string = variableAssignmentApis[type].url + (params.toString().length ? `?${params.toString()}` : ""); + const apiUrl: string = assignmentApi.url + (params.toString().length ? `?${params.toString()}` : ""); - return this.httpClient().get(apiUrl).catch(e => { + const candidates = await this.httpClient().get(apiUrl).catch(e => { throw new FatalError(`Problem getting variables assignment values for type ${type}: ${e}`); }); + + return (Array.isArray(candidates) ? candidates : []) + .map(candidate => assignmentApi.toAssignment(candidate)) + .filter(assignment => !!assignment.value); } } diff --git a/src/commands/configuration-management/interfaces/variable-assignment-apis.constants.ts b/src/commands/configuration-management/interfaces/variable-assignment-apis.constants.ts index ae930750..1b389d06 100644 --- a/src/commands/configuration-management/interfaces/variable-assignment-apis.constants.ts +++ b/src/commands/configuration-management/interfaces/variable-assignment-apis.constants.ts @@ -1,12 +1,38 @@ +export interface VariableAssignment { + value: string; + name: string; +} + export interface VariableAssignmentApi { url: string; + toAssignment: (candidate: any) => VariableAssignment; } +const connectionName = (connection: any): string => { + const parts = [connection?.authProvider?.label ?? connection?.authProvider?.name, connection?.username].filter(Boolean); + return parts.length ? parts.join(" - ") : connection?.id; +}; + export const variableAssignmentApis: { [key: string]: VariableAssignmentApi } = { DATA_MODEL: { - url: "/package-manager/api/compute-pools/pools-with-data-models" + url: "/package-manager/api/compute-pools/pools-with-data-models", + toAssignment: candidate => ({ + value: candidate?.dataModel?.dataModelId, + name: [candidate?.pool?.name, candidate?.dataModel?.name].filter(Boolean).join(" / ") || candidate?.dataModel?.dataModelId, + }), }, CONNECTION: { - url: "/process-automation-v2/api/connections" - } -}; \ No newline at end of file + url: "/process-automation-v2/api/connections", + toAssignment: candidate => ({ + value: candidate?.id, + name: connectionName(candidate), + }), + }, + DATA_POOL_ID: { + url: "/integration/api/pools", + toAssignment: candidate => ({ + value: candidate?.id, + name: candidate?.name ?? candidate?.id, + }), + }, +}; diff --git a/tests/commands/configuration-management/list-assignments.spec.ts b/tests/commands/configuration-management/list-assignments.spec.ts index ff086679..329ceb2d 100644 --- a/tests/commands/configuration-management/list-assignments.spec.ts +++ b/tests/commands/configuration-management/list-assignments.spec.ts @@ -9,56 +9,96 @@ describe("List assignments", () => { const DATA_MODEL_URL = "https://myTeam.celonis.cloud/package-manager/api/compute-pools/pools-with-data-models"; const CONNECTIONS_URL = "https://myTeam.celonis.cloud/process-automation-v2/api/connections?param1=value1¶m2=value2"; + const DATA_POOLS_URL = "https://myTeam.celonis.cloud/integration/api/pools"; - it("Should list assignments for supported type and non-json response", async () => { - const mockAssignmentValues = [ - {id: "id-1"}, - {id: "id-2"} - ]; - mockAxiosGet(DATA_MODEL_URL, mockAssignmentValues); + const dataModelCandidate = (poolName: string, dataModelId: string, dataModelName: string) => ({ + pool: {id: "pool-" + dataModelId, name: poolName}, + dataModel: {dataModelId, name: dataModelName, poolId: "pool-" + dataModelId}, + lastLoaded: null, + businessGraphDataModel: false, + }); + + it("Should list data model assignments as value and name", async () => { + mockAxiosGet(DATA_MODEL_URL, [ + dataModelCandidate("Pool 1", "dm-1", "Model 1"), + dataModelCandidate("Pool 2", "dm-2", "Model 2"), + ]); await new VariableCommandService(testContext).listAssignments("DATA_MODEL", false, ""); expect(loggingTestTransport.logMessages.length).toBe(2); - expect(loggingTestTransport.logMessages[0].message).toContain('{"id":"id-1"}'); - expect(loggingTestTransport.logMessages[1].message).toContain('{"id":"id-2"}'); + expect(loggingTestTransport.logMessages[0].message).toContain('{"value":"dm-1","name":"Pool 1 / Model 1"}'); + expect(loggingTestTransport.logMessages[1].message).toContain('{"value":"dm-2","name":"Pool 2 / Model 2"}'); expect(mockedAxiosInstance.get).toHaveBeenCalledWith(DATA_MODEL_URL, expect.anything()) }) it("Should export assignments for supported type and json response", async () => { - const mockAssignmentValues = [ - {id: "id-1"}, - {id: "id-2"} - ]; - mockAxiosGet(DATA_MODEL_URL, mockAssignmentValues); + mockAxiosGet(DATA_MODEL_URL, [ + dataModelCandidate("Pool 1", "dm-1", "Model 1"), + dataModelCandidate("Pool 2", "dm-2", "Model 2"), + ]); await new VariableCommandService(testContext).listAssignments("DATA_MODEL", true, ""); expect(loggingTestTransport.logMessages.length).toBe(1); expect(loggingTestTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage); - expect(getJsonFromDownloadedFile()).toEqual(mockAssignmentValues); + expect(getJsonFromDownloadedFile()).toEqual([ + {value: "dm-1", name: "Pool 1 / Model 1"}, + {value: "dm-2", name: "Pool 2 / Model 2"}, + ]); }) it("Should contain url params in the url", async () => { - const mockAssignmentValues = [{id: "id-1"}]; - mockAxiosGet(CONNECTIONS_URL, mockAssignmentValues); + mockAxiosGet(CONNECTIONS_URL, [{id: "connection-1"}]); await new VariableCommandService(testContext).listAssignments("CONNECTION", false, "param1=value1,param2=value2"); expect(mockedAxiosInstance.get).toHaveBeenCalledWith(CONNECTIONS_URL, expect.anything()) }) + it("Should name connections by their provider and username", async () => { + mockAxiosGet(CONNECTIONS_URL, [ + {id: "connection-1", username: "jane@celonis.com", authProvider: {name: "celonis", label: "Celonis"}}, + {id: "connection-2"}, + ]); + + await new VariableCommandService(testContext).listAssignments("CONNECTION", true, "param1=value1,param2=value2"); + + expect(getJsonFromDownloadedFile()).toEqual([ + {value: "connection-1", name: "Celonis - jane@celonis.com"}, + {value: "connection-2", name: "connection-2"}, + ]); + }) + + it("Should list data pools as assignments for the DATA_POOL_ID type", async () => { + mockAxiosGet(DATA_POOLS_URL, [ + {id: "pool-1", name: "Pool 1", dataPoolType: "DATA_JOBS"}, + {id: "pool-2", name: "Pool 2", dataPoolType: "DATA_JOBS"}, + ]); + + await new VariableCommandService(testContext).listAssignments("DATA_POOL_ID", true, ""); + + expect(mockedAxiosInstance.get).toHaveBeenCalledWith(DATA_POOLS_URL, expect.anything()); + expect(getJsonFromDownloadedFile()).toEqual([ + {value: "pool-1", name: "Pool 1"}, + {value: "pool-2", name: "Pool 2"}, + ]); + }) + + it("Should skip candidates without a value", async () => { + mockAxiosGet(DATA_POOLS_URL, [{name: "Pool without id"}, {id: "pool-1", name: "Pool 1"}]); + + await new VariableCommandService(testContext).listAssignments("DATA_POOL_ID", true, ""); + + expect(getJsonFromDownloadedFile()).toEqual([{value: "pool-1", name: "Pool 1"}]); + }) + it("Should throw error for unsupported variable types", async () => { const type: string = "DUMMY_UNSUPPORTED_TYPE"; - try { - await new VariableCommandService(testContext).listAssignments(type, false, ""); - } catch (e) { - if (!(e.message === `Variable type ${type} not supported.`)) { - fail(); - } - } + await expect(new VariableCommandService(testContext).listAssignments(type, false, "")) + .rejects.toThrow(`Variable type ${type} not supported.`); }) -}) \ No newline at end of file +})