Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ export class BatchImportExportApi {
});
}

public async findPackagesByKeysAndVersion(packageKeysWithVersion: string[], withDependencies: boolean = false): Promise<PackageExportTransport[]> {
const queryParams = new URLSearchParams();

packageKeysWithVersion.forEach(keyWithVersion => queryParams.append("packageKeysWithVersion", keyWithVersion));
queryParams.set("withDependencies", withDependencies.toString());

return this.httpClient().get(`/package-manager/api/core/packages/versions/export/list?${queryParams.toString()}`).catch(e => {
throw new FatalError(`Problem getting packages by keys and versions: ${e}`);
});
}

public async exportPackages(packageKeys: string[], withDependencies: boolean): Promise<Buffer> {
const queryParams = new URLSearchParams();
packageKeys.forEach(packageKey => queryParams.append("packageKeys", packageKey));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ export class BatchImportExportService {
});
}

public async findAndExportListOfActivePackages(flavors: string[], packageKeys: string[], withDependencies: boolean): Promise<void> {
public async findAndExportListOfPackages(flavors: string[], packageKeys: string[], keysByVersion: string[], withDependencies: boolean): Promise<void> {
let packagesToExport: PackageExportTransport[];

if (packageKeys.length) {
if (keysByVersion.length) {
packagesToExport = await this.batchImportExportApi.findPackagesByKeysAndVersion(keysByVersion, withDependencies);
} else if (packageKeys.length) {
packagesToExport = await this.batchImportExportApi.findActivePackagesByKeys(packageKeys, withDependencies);
} else {
} else {
packagesToExport = await this.batchImportExportApi.findAllActivePackages(flavors, withDependencies);
}

Expand All @@ -55,6 +57,13 @@ export class BatchImportExportService {
this.exportListOfPackages(packagesToExport);
}

public async listPackagesByKeysWithVersion(keysByVersion: string[], withDependencies: boolean): Promise<void> {
const exportedPackages = await this.batchImportExportApi.findPackagesByKeysAndVersion(keysByVersion, withDependencies);
exportedPackages.forEach(pkg => {
logger.info(`${pkg.name} - Key: "${pkg.key}"`);
});
}

public async batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean): Promise<void> {
let exportedPackagesData: Buffer;
if (packageKeys) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ export class ConfigCommandService {
this.diffService = new DiffService(context);
}

public async listActivePackages(jsonResponse: boolean, flavors: string[], withDependencies: boolean, packageKeys: string[], variableValue: string, variableType: string): Promise<void> {
public async listPackages(jsonResponse: boolean, flavors: string[], withDependencies: boolean, packageKeys: string[], keysByVersion: string[], variableValue: string, variableType: string): Promise<void> {
if (variableValue) {
await this.listPackagesByVariableValue(jsonResponse, flavors, variableValue, variableType);
return;
}

if (jsonResponse) {
await this.batchImportExportService.findAndExportListOfActivePackages(flavors ?? [], packageKeys ?? [], withDependencies)
await this.batchImportExportService.findAndExportListOfPackages(flavors ?? [], packageKeys ?? [], keysByVersion ?? [], withDependencies);
} else if (keysByVersion) {
await this.batchImportExportService.listPackagesByKeysWithVersion(keysByVersion, withDependencies);
} else {
await this.batchImportExportService.listActivePackages(flavors ?? []);
}
Expand Down
14 changes: 9 additions & 5 deletions src/commands/configuration-management/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ class Module extends IModule {
public register(context: Context, configurator: Configurator): void {
const configCommand = configurator.command("config");
configCommand.command("list")
.description("Command to list active packages that can be exported")
.description("Command to list packages")
.option("--json", "Return response as json type", "")
.option("--flavors <flavors...>", "Lists only active packages of the given flavors")
.option("--withDependencies", "Include dependencies", "")
.option("--packageKeys <packageKeys...>", "Lists only given package keys")
.option("--packageKeys <packageKeys...>", "Lists only active versions of given package keys")
.option("--keysByVersion <keysByVersion...>", "Lists packages by given key and version [packageKey.version]")
.option("--variableValue <variableValue>", "Variable value for filtering packages by.")
.option("--variableType <variableType>", "Variable type for filtering packages by.")
.action(this.listActivePackages);
.action(this.listPackages);

configCommand.command("export")
.description("Command to export package configs")
Expand Down Expand Up @@ -133,8 +134,11 @@ class Module extends IModule {
.action(this.listAssignments);
}

private async listActivePackages(context: Context, command: Command, options: OptionValues): Promise<void> {
await new ConfigCommandService(context).listActivePackages(options.json, options.flavors, options.withDependencies, options.packageKeys, options.variableValue, options.variableType);
private async listPackages(context: Context, command: Command, options: OptionValues): Promise<void> {
if (options.packageKeys && options.keysByVersion) {
throw new Error("Please provide either --packageKeys or --keysByVersion, but not both.");
}
await new ConfigCommandService(context).listPackages(options.json, options.flavors, options.withDependencies, options.packageKeys, options.keysByVersion, options.variableValue, options.variableType);
}

private async batchExportPackages(context: Context, command: Command, options: OptionValues): Promise<void> {
Expand Down
75 changes: 67 additions & 8 deletions tests/commands/configuration-management/config-list.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as path from "path";
import { stringify } from "../../../src/core/utils/json";
import { PacmanApiUtils } from "../../utls/pacman-api.utils";
import { mockAxiosGet } from "../../utls/http-requests-mock";
import { ConfigCommandService } from "../../../src/commands/configuration-management/config-command.service";
Expand Down Expand Up @@ -33,7 +32,7 @@ describe("Config list", () => {

mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/list?" + urlParams.toString(), [firstPackage, secondPackage]);

await new ConfigCommandService(testContext).listActivePackages(false, flavorsArray, false, [], null, null);
await new ConfigCommandService(testContext).listPackages(false, flavorsArray, false, [], undefined, null, null);

expect(loggingTestTransport.logMessages.length).toBe(2);
expect(loggingTestTransport.logMessages[0].message).toContain(`${firstPackage.name} - Key: "${firstPackage.key}"`);
Expand All @@ -50,7 +49,7 @@ describe("Config list", () => {
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/list?withDependencies=false", [{...firstPackage}, {...secondPackage}]);
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/packages/with-variable-assignments?type=DATA_MODEL", [studioPackage]);

await new ConfigCommandService(testContext).listActivePackages(true, [], false, [], null, null);
await new ConfigCommandService(testContext).listPackages(true, [], false, [], undefined, null, null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

Expand Down Expand Up @@ -96,7 +95,7 @@ describe("Config list", () => {
};
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/compute-pools/data-models/details", [dataModelDetailResponse]);

await new ConfigCommandService(testContext).listActivePackages(true, [], true, [], null, null);
await new ConfigCommandService(testContext).listPackages(true, [], true, [], undefined, null, null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

Expand All @@ -121,7 +120,7 @@ describe("Config list", () => {
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/list-by-keys?packageKeys=key-1&packageKeys=key-2&withDependencies=false", [{...firstPackage}, {...secondPackage}]);
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/packages/with-variable-assignments?type=DATA_MODEL", [studioPackage]);

await new ConfigCommandService(testContext).listActivePackages(true, [], false, [firstPackage.key, secondPackage.key], null, null);
await new ConfigCommandService(testContext).listPackages(true, [], false, [firstPackage.key, secondPackage.key], undefined, null, null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

Expand Down Expand Up @@ -167,7 +166,7 @@ describe("Config list", () => {
};
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/compute-pools/data-models/details", [dataModelDetailResponse]);

await new ConfigCommandService(testContext).listActivePackages(true, [], true, [firstPackage.key, secondPackage.key], null, null);
await new ConfigCommandService(testContext).listPackages(true, [], true, [firstPackage.key, secondPackage.key], undefined, null, null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

Expand All @@ -191,7 +190,7 @@ describe("Config list", () => {
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/list-by-variable-value?variableValue=1", [{...firstPackage}, {...secondPackage}]);
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/packages/with-variable-assignments?type=DATA_MODEL", []);

await new ConfigCommandService(testContext).listActivePackages(false, [], false, [], "1", null);
await new ConfigCommandService(testContext).listPackages(false, [], false, [], undefined, "1", null);

expect(loggingTestTransport.logMessages.length).toBe(2);
expect(loggingTestTransport.logMessages[0].message).toContain(`${firstPackage.name} - Key: "${firstPackage.key}"`);
Expand All @@ -205,7 +204,7 @@ describe("Config list", () => {
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/list-by-variable-value?variableValue=1", [{...firstPackage}, {...secondPackage}]);
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/packages/with-variable-assignments?type=DATA_MODEL", []);

await new ConfigCommandService(testContext).listActivePackages(true, [], false, [], "1", null);
await new ConfigCommandService(testContext).listPackages(true, [], false, [], undefined, "1", null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

Expand All @@ -215,4 +214,64 @@ describe("Config list", () => {
expect(exportedTransports.length).toBe(2);
})

it("Should list packages by keysByVersion for non-json response", async () => {
const firstPackage = PacmanApiUtils.buildPackageExportTransport("key-1", "name-1");
const secondPackage = PacmanApiUtils.buildPackageExportTransport("key-2", "name-2");

const keysByVersion = ["key-1.1.0.0", "key-2.1.0.1"];
mockAxiosGet(
"https://myTeam.celonis.cloud/package-manager/api/core/packages/versions/export/list?packageKeysWithVersion=key-1.1.0.0&packageKeysWithVersion=key-2.1.0.1&withDependencies=false",
[firstPackage, secondPackage]
);

await new ConfigCommandService(testContext).listPackages(false, [], false, undefined, keysByVersion, null, null);

expect(loggingTestTransport.logMessages.length).toBe(2);
expect(loggingTestTransport.logMessages[0].message).toContain(`${firstPackage.name} - Key: "${firstPackage.key}"`);
expect(loggingTestTransport.logMessages[1].message).toContain(`${secondPackage.name} - Key: "${secondPackage.key}"`);
})

it("Should list packages by keysByVersion with withDependencies for non-json response", async () => {
const firstPackage = PacmanApiUtils.buildPackageExportTransport("key-1", "name-1");
const secondPackage = PacmanApiUtils.buildPackageExportTransport("key-2", "name-2");

const keysByVersion = ["key-1.1.0.0", "key-2.1.0.1"];
mockAxiosGet(
"https://myTeam.celonis.cloud/package-manager/api/core/packages/versions/export/list?packageKeysWithVersion=key-1.1.0.0&packageKeysWithVersion=key-2.1.0.1&withDependencies=true",
[firstPackage, secondPackage]
);

await new ConfigCommandService(testContext).listPackages(false, [], true, undefined, keysByVersion, null, null);

expect(loggingTestTransport.logMessages.length).toBe(2);
})

it("Should list packages by keysByVersion for json response", async () => {
const firstPackage = PacmanApiUtils.buildPackageExportTransport("key-1", "name-1");
const secondPackage = PacmanApiUtils.buildPackageExportTransport("key-2", "name-2");

const studioPackage: ContentNodeTransport = PacmanApiUtils.buildContentNodeTransport("key-1", "spaceId-1");
const keysByVersion = ["key-1.1.0.0", "key-2.1.0.1"];

mockAxiosGet(
"https://myTeam.celonis.cloud/package-manager/api/core/packages/versions/export/list?packageKeysWithVersion=key-1.1.0.0&packageKeysWithVersion=key-2.1.0.1&withDependencies=false",
[{...firstPackage}, {...secondPackage}]
);
mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/packages/with-variable-assignments?type=DATA_MODEL", [studioPackage]);

await new ConfigCommandService(testContext).listPackages(true, [], false, [], keysByVersion, null, null);

const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];

expect(mockWriteFileSync).toHaveBeenCalledWith(path.resolve(process.cwd(), expectedFileName), expect.any(String), {encoding: "utf-8"});

const exportedTransports = JSON.parse(mockWriteFileSync.mock.calls[0][1]) as PackageExportTransport[];
expect(exportedTransports.length).toBe(2);

const exportedFirstPackage = exportedTransports.filter(transport => transport.key === firstPackage.key)[0];
const exportedSecondPackage = exportedTransports.filter(transport => transport.key === secondPackage.key)[0];

expect(exportedSecondPackage).toEqual(secondPackage);
expect(exportedFirstPackage).toEqual({...firstPackage, spaceId: "spaceId-1"});
})
})
56 changes: 56 additions & 0 deletions tests/commands/configuration-management/module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe("Configuration Management Module - Action Validations", () => {
mockCommand = {} as Command;

mockConfigCommandService = {
listPackages: jest.fn().mockResolvedValue(undefined),
batchExportPackages: jest.fn().mockResolvedValue(undefined),
batchImportPackages: jest.fn().mockResolvedValue(undefined),
} as any;
Expand All @@ -31,6 +32,61 @@ describe("Configuration Management Module - Action Validations", () => {
(NodeDependencyService as jest.MockedClass<typeof NodeDependencyService>).mockImplementation(() => mockNodeDependencyService);
});

describe("listActivePackages validation", () => {
describe("packageKeys and keysByVersion validation", () => {
it("should throw error when both packageKeys and keysByVersion are provided", async () => {
const options: OptionValues = {
packageKeys: ["package1", "package2"],
keysByVersion: ["package3.1.0.0", "package4.1.0.0"],
};

await expect(
(module as any).listPackages(testContext, mockCommand, options)
).rejects.toThrow("Please provide either --packageKeys or --keysByVersion, but not both.");

expect(mockConfigCommandService.listPackages).not.toHaveBeenCalled();
});

it("should pass validation when only packageKeys is provided", async () => {
const options: OptionValues = {
packageKeys: ["package1", "package2"],
json: true,
};

await (module as any).listPackages(testContext, mockCommand, options);

expect(mockConfigCommandService.listPackages).toHaveBeenCalledWith(
true,
undefined,
undefined,
["package1", "package2"],
undefined,
undefined,
undefined
);
});

it("should pass validation when only keysByVersion is provided", async () => {
const options: OptionValues = {
keysByVersion: ["package3.1.0.0", "package4.1.0.0"],
json: true,
};

await (module as any).listPackages(testContext, mockCommand, options);

expect(mockConfigCommandService.listPackages).toHaveBeenCalledWith(
true,
undefined,
undefined,
undefined,
["package3.1.0.0", "package4.1.0.0"],
undefined,
undefined
);
});
});
});

describe("batchExportPackages validation", () => {
describe("packageKeys and keysByVersion validation", () => {
it("should throw error when both packageKeys and keysByVersion are provided", async () => {
Expand Down