Skip to content

Commit

Permalink
Merge pull request #168 from celonis/TA-2785-list-variables-command
Browse files Browse the repository at this point in the history
[TA-2785] List variables command
  • Loading branch information
LaberionAjvazi authored Jan 31, 2024
2 parents 9701dbb + 5c8960e commit c80248a
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 3 deletions.
9 changes: 9 additions & 0 deletions src/commands/config.command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {batchImportExportService} from "../services/package-manager/batch-import-export-service";
import {variableService} from "../services/package-manager/variable-service";

export class ConfigCommand {

Expand All @@ -10,6 +11,14 @@ export class ConfigCommand {
}
}

public async listVariables(jsonResponse: boolean, keysByVersion: string[], keysByVersionFile: string): Promise<void> {
if (jsonResponse) {
await variableService.exportVariables(keysByVersion, keysByVersionFile);
} else {
await variableService.listVariables(keysByVersion, keysByVersionFile);
}
}

public batchExportPackages(packageKeys: string[], withDependencies: boolean = false): Promise<void> {
return batchImportExportService.batchExportPackages(packageKeys, withDependencies);
}
Expand Down
17 changes: 17 additions & 0 deletions src/content-cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ export class Config {
return program;
}

public static listVariables(program: CommanderStatic): CommanderStatic {
program
.command("listVariables")
.description("Command to list versioned variables of packages")
.option("-p, --profile <profile>", "Profile which you want to use to list packages")
.option("--json", "Return response as json type", "")
.option("--keysByVersion <keysByVersion...>", "Mapping of package keys and versions", "")
.option("--keysByVersionFile <keysByVersionFile>", "Package keys by version mappings file path.", "")
.action(async cmd => {
await new ConfigCommand().listVariables(cmd.json, cmd.keysByVersion, cmd.keysByVersionFile);
process.exit();
})

return program;
}

public static export(program: CommanderStatic): CommanderStatic {
program
.command("export")
Expand All @@ -45,6 +61,7 @@ process.on("unhandledRejection", (e, promise) => {

const loadAllCommands = () => {
Config.list(commander);
Config.listVariables(commander);
Config.export(commander);
commander.parse(process.argv);
};
Expand Down
58 changes: 55 additions & 3 deletions src/services/package-manager/variable-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { v4 as uuidv4 } from "uuid";
import {FatalError, logger} from "../../util/logger";
import {FileService, fileService} from "../file-service";
import {URLSearchParams} from "url";
import {studioService} from "../studio/studio.service";
import {batchImportExportApi} from "../../api/batch-import-export-api";
import {PackageKeyAndVersionPair, VariableManifestTransport} from "../../interfaces/package-export-transport";

class VariableService {

Expand All @@ -33,9 +36,21 @@ class VariableService {
const parsedParams = this.parseParams(params);
const assignments = await variablesApi.getCandidateAssignments(type, parsedParams);

const filename = uuidv4() + ".json";
fileService.writeToFileWithGivenName(JSON.stringify(assignments), filename);
logger.info(FileService.fileDownloadedMessage + filename);
this.exportToJson(assignments)
}

public async listVariables(keysByVersion: string[], keysByVersionFile: string): Promise<void> {
const variableManifests = await this.getVersionedVariablesByKeyVersionPairs(keysByVersion, keysByVersionFile);

variableManifests.forEach(variableManifest => {
logger.info(JSON.stringify(variableManifest));
});
}

public async exportVariables(keysByVersion: string[], keysByVersionFile: string): Promise<void> {
const variableManifests = await this.getVersionedVariablesByKeyVersionPairs(keysByVersion, keysByVersionFile);

this.exportToJson(variableManifests);
}

private parseParams(params?: string): URLSearchParams {
Expand All @@ -54,6 +69,43 @@ class VariableService {

return queryParams;
}

private async getVersionedVariablesByKeyVersionPairs(keysByVersion: string[], keysByVersionFile: string): Promise<VariableManifestTransport[]> {
const variablesExportRequest: PackageKeyAndVersionPair[] = await this.buildKeyVersionPairs(keysByVersion, keysByVersionFile);

const variableManifests = await batchImportExportApi.findVariablesWithValuesByPackageKeysAndVersion(variablesExportRequest);
return studioService.fixConnectionVariables(variableManifests);
}

private async buildKeyVersionPairs(keysByVersion: string[], keysByVersionFile: string): Promise<PackageKeyAndVersionPair[]> {
let variablesExportRequest: PackageKeyAndVersionPair[] = [];

if (keysByVersion.length) {
variablesExportRequest = this.buildKeyAndVersionPairsFromArrayInput(keysByVersion);
} else if (!keysByVersion.length && keysByVersionFile.length) {
variablesExportRequest = await fileService.readFileToJson(keysByVersionFile);
} else {
throw new FatalError("Please provide keysByVersion mappings or file path!");
}

return variablesExportRequest;
}

private buildKeyAndVersionPairsFromArrayInput(keysByVersion: string[]): PackageKeyAndVersionPair[] {
return keysByVersion.map(keyAndVersion => {
const keyAndVersionSplit = keyAndVersion.split(":");
return {
packageKey: keyAndVersionSplit[0],
version: keyAndVersionSplit[1]
};
});
}

private exportToJson(data: any): void {
const filename = uuidv4() + ".json";
fileService.writeToFileWithGivenName(JSON.stringify(data), filename);
logger.info(FileService.fileDownloadedMessage + filename);
}
}

export const variableService = new VariableService();
149 changes: 149 additions & 0 deletions tests/config/config-list-variables.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import {ConfigCommand} from "../../src/commands/config.command";
import {mockWriteFileSync, testTransport} from "../jest.setup";
import {FileService} from "../../src/services/file-service";
import * as path from "path";
import {PackageKeyAndVersionPair, VariableManifestTransport} from "../../src/interfaces/package-export-transport";
import {PackageManagerVariableType} from "../../src/interfaces/package-manager.interfaces";
import {mockAxiosPost, mockedPostRequestBodyByUrl} from "../utls/http-requests-mock";
import {parse} from "../../src/util/yaml";
import * as fs from "fs";

describe("Config listVariables", () => {

const firstManifest: VariableManifestTransport = {
packageKey: "key-1",
version: "1.0.0",
variables: [
{
key: "key1-var",
type: PackageManagerVariableType.DATA_MODEL,
value: "dm-id" as unknown as object,
metadata: {}
},
{
key: "key-1-connection",
type: PackageManagerVariableType.CONNECTION,
value: {
appName: "celonis",
connectionId: "connection-id"
} as unknown as object,
metadata: null
}
]
};

const secondManifest: VariableManifestTransport = {
packageKey: "key-2",
version: "1.0.0",
variables: [
{
key: "key2-var",
type: PackageManagerVariableType.CONNECTION,
value: {
appName: "celonis",
connectionId: "connection-id"
} as unknown as object,
metadata: {
appName: "celonis"
}
}
]
};

const fixedVariableManifests: VariableManifestTransport[] = [
{
...firstManifest,
variables: [
{
...firstManifest.variables[0]
},
{
...firstManifest.variables[1],
metadata: {
appName: "celonis"
}
}
]
},
{
...secondManifest
}
];

const packageKeyAndVersionPairs: PackageKeyAndVersionPair[] = [
{
packageKey: "key-1",
version: "1.0.0"
},
{
packageKey: "key-2",
version: "1.0.0"
}
];

beforeEach(() => {
mockAxiosPost("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments", [{...firstManifest}, {...secondManifest}]);
})

it("Should list fixed variables for non-json response", async () => {
await new ConfigCommand().listVariables(false, ["key-1:1.0.0", "key-2:1.0.0"], null);

expect(testTransport.logMessages.length).toBe(2);
expect(testTransport.logMessages[0].message).toContain(JSON.stringify(fixedVariableManifests[0]));
expect(testTransport.logMessages[1].message).toContain(JSON.stringify(fixedVariableManifests[1]));

const variableExportRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments"));
expect(variableExportRequest).toEqual(packageKeyAndVersionPairs);
})

it("Should export fixed variables for json response", async () => {
await new ConfigCommand().listVariables(true, ["key-1:1.0.0", "key-2:1.0.0"], null);

expect(testTransport.logMessages.length).toBe(1);
expect(testTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage);

const expectedFileName = testTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];
expect(mockWriteFileSync).toHaveBeenCalledWith(path.resolve(process.cwd(), expectedFileName), JSON.stringify(fixedVariableManifests), {encoding: "utf-8"});

const variableExportRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments"));
expect(variableExportRequest).toEqual(packageKeyAndVersionPairs);
})

it("Should list fixed variables for non-json response and keysByVersion file mapping", async () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(packageKeyAndVersionPairs));

await new ConfigCommand().listVariables(false, [], "key_version_mapping.json");

expect(testTransport.logMessages.length).toBe(2);
expect(testTransport.logMessages[0].message).toContain(JSON.stringify(fixedVariableManifests[0]));
expect(testTransport.logMessages[1].message).toContain(JSON.stringify(fixedVariableManifests[1]));

const variableExportRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments"));
expect(variableExportRequest).toEqual(packageKeyAndVersionPairs);
})

it("Should export fixed variables for json response and keysByVersion file mapping", async () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(packageKeyAndVersionPairs));

await new ConfigCommand().listVariables(true, [], "key_version_mapping.json");

expect(testTransport.logMessages.length).toBe(1);
expect(testTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage);

const expectedFileName = testTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];
expect(mockWriteFileSync).toHaveBeenCalledWith(path.resolve(process.cwd(), expectedFileName), JSON.stringify(fixedVariableManifests), {encoding: "utf-8"});

const variableExportRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments"));
expect(variableExportRequest).toEqual(packageKeyAndVersionPairs);
})

it("Should throw error if no mapping or file path is provided", async () => {
try {
await new ConfigCommand().listVariables(true, [], "");
} catch (e) {
expect(e.message).toEqual("Please provide keysByVersion mappings or file path!");
}
})
})

0 comments on commit c80248a

Please sign in to comment.