diff --git a/docs/command-graph.html b/docs/command-graph.html
index e20f2ffe..752514fb 100644
--- a/docs/command-graph.html
+++ b/docs/command-graph.html
@@ -361,6 +361,9 @@
{ id: "config_versions_get", label: "get", group: "command", path: "config versions get",
description: "Get version metadata for a specific package version",
options: ["-p, --profile ", "--packageKey ", "--packageVersion (specific version or \"LATEST\")", "--json", "-h, --help"] },
+ { id: "config_versions_list", label: "list", group: "command", path: "config versions list",
+ description: "List all created versions of a package or branch",
+ options: ["-p, --profile ", "--packageKey (use @ for a branch)", "--json", "-h, --help"] },
{ id: "config_versions_create", label: "create", group: "command", path: "config versions create",
description: "Create a new version for a package",
options: ["-p, --profile ", "--packageKey ", "--packageVersion (required if versionBumpOption is NONE)", "--versionBumpOption (NONE or PATCH, default: \"NONE\")", "--summaryOfChanges ", "--nodeFilterKeys (default: all nodes)", "--json", "-h, --help"] },
@@ -521,7 +524,7 @@
["config_branch_merge_area","config_branch_merge_preview"],["config_branch_merge_area","config_branch_merge_apply"],
["area_config","config_metadata_area"],["config_metadata_area","config_metadata_export"],
["area_config","config_versions_area"],["config_versions_area","config_versions_get"],
- ["config_versions_area","config_versions_create"],
+ ["config_versions_area","config_versions_list"],["config_versions_area","config_versions_create"],
["area_config","config_variables_area"],["config_variables_area","config_variables_list"],
["area_config","config_nodes_area"],
["config_nodes_area","config_nodes_get"],["config_nodes_area","config_nodes_create"],
diff --git a/docs/user-guide/config-commands.md b/docs/user-guide/config-commands.md
index a9893d72..086ff699 100644
--- a/docs/user-guide/config-commands.md
+++ b/docs/user-guide/config-commands.md
@@ -10,7 +10,7 @@ The `config` command group manages a package and its resources — importing a s
- [`config package validate`](#validate-package-configurations-config-package-validate) — validate a package's staging version
- [`config package list`](#list-packages-config-package-list) — list packages (staging by default)
- [`config nodes …`](#finding-nodes) — work with individual nodes
- - [`config versions …`](#package-version) — read and create package versions
+ - [`config versions …`](#package-version) — read, list and create package versions
- [`config variables list`](#listing--mapping-variables) — read package variables
- `config metadata export` — check whether packages have unpublished changes
- **Team-to-Team Copy (batch) commands** — bulk multi-package transport, now under [`t2tc package`](./t2tc-commands.md):
@@ -39,7 +39,7 @@ This applies to every command that reads or modifies a single package or its nod
- `config nodes get`, `config nodes list`, `config nodes diff`, `config nodes dependencies list`
- `config nodes create`, `config nodes update`, `config nodes archive`
- `config variables list`
-- `config versions get`, `config versions create`
+- `config versions get`, `config versions list`, `config versions create`
- `config package validate`, `config package import`, `config package export`, `config metadata export`
- `t2tc package export`, `t2tc package import`, `t2tc package diff`
@@ -440,6 +440,28 @@ To export the version metadata as a JSON file instead of displaying it in the co
content-cli config versions get --packageKey --packageVersion --json
```
+### List Package Versions
+
+To list all created versions of a package, use the following command:
+
+```bash
+content-cli config versions list --packageKey
+```
+
+Branches are packages too, so the same command lists the versions of a branch:
+
+```bash
+content-cli config versions list --packageKey @
+```
+
+The command prints one line of version metadata per version. A package without versions prints `Package has no versions.`
+
+To export the list as a JSON file instead, use the `--json` option:
+
+```bash
+content-cli config versions list --packageKey --json
+```
+
### Create Package Version
To create a new version for a package, use the following command:
diff --git a/src/commands/configuration-management/api/package-version-api.ts b/src/commands/configuration-management/api/package-version-api.ts
index b088f43f..4d97560c 100644
--- a/src/commands/configuration-management/api/package-version-api.ts
+++ b/src/commands/configuration-management/api/package-version-api.ts
@@ -14,6 +14,14 @@ export class PackageVersionApi {
this.httpClient = () => context.httpClient;
}
+ public async findAll(packageKey: string): Promise {
+ return this.httpClient()
+ .get(`/pacman/api/core/packages/${packageKey}/versions`)
+ .catch(e => {
+ throw new FatalError(`Problem listing versions of Package with key '${packageKey}': ${e}`);
+ });
+ }
+
public async findOne(packageKey: string, version: string): Promise {
return this.httpClient()
.get(`/pacman/api/core/packages/${packageKey}/versions/${version}`)
diff --git a/src/commands/configuration-management/module.ts b/src/commands/configuration-management/module.ts
index 90691247..fe994e1f 100644
--- a/src/commands/configuration-management/module.ts
+++ b/src/commands/configuration-management/module.ts
@@ -220,6 +220,12 @@ class Module extends IModule {
.option("--json", "Return the response as a JSON file")
.action(this.getPackageVersion)
+ configVersionCommand.command("list")
+ .description("List all created versions of a package or branch")
+ .requiredOption("--packageKey ", "Identifier of the package. Use @ for a branch.")
+ .option("--json", "Return the response as a JSON file")
+ .action(this.listPackageVersions);
+
configVersionCommand.command("create")
.description("Create a new version for a package")
.requiredOption("--packageKey ", "Identifier of the package")
@@ -451,6 +457,10 @@ class Module extends IModule {
await new PackageVersionCommandService(context).getPackageVersion(options.packageKey, options.packageVersion, options.json);
}
+ private async listPackageVersions(context: Context, command: Command, options: OptionValues): Promise {
+ await new PackageVersionCommandService(context).listPackageVersions(options.packageKey, options.json);
+ }
+
private async createPackageVersion(context: Context, command: Command, options: OptionValues): Promise {
const hasExplicitVersion = !!options.packageVersion;
const hasVersionBump = options.versionBumpOption && options.versionBumpOption !== "NONE";
diff --git a/src/commands/configuration-management/package-version-command.service.ts b/src/commands/configuration-management/package-version-command.service.ts
index 262d87a3..33a67ab6 100644
--- a/src/commands/configuration-management/package-version-command.service.ts
+++ b/src/commands/configuration-management/package-version-command.service.ts
@@ -13,6 +13,10 @@ export class PackageVersionCommandService {
await this.packageVersionService.findPackageVersion(packageKey, version, jsonResponse);
}
+ public async listPackageVersions(packageKey: string, jsonResponse: boolean): Promise {
+ await this.packageVersionService.listPackageVersions(packageKey, jsonResponse);
+ }
+
public async createPackageVersion(
packageKey: string,
version: string | undefined,
diff --git a/src/commands/configuration-management/package-version.service.ts b/src/commands/configuration-management/package-version.service.ts
index f4aa60f2..c2ee5893 100644
--- a/src/commands/configuration-management/package-version.service.ts
+++ b/src/commands/configuration-management/package-version.service.ts
@@ -31,6 +31,19 @@ export class PackageVersionService {
}
}
+ public async listPackageVersions(packageKey: string, jsonResponse: boolean): Promise {
+ const packageVersions: PackageVersionTransport[] = await this.packageVersionApi.findAll(packageKey);
+ if (jsonResponse) {
+ const filename = uuidv4() + ".json";
+ const writtenFilename = await this.cuiFileService.writeToFileWithGivenName(JSON.stringify(packageVersions, null, 2), filename);
+ logger.info(FileService.fileDownloadedMessage + writtenFilename);
+ } else if (packageVersions.length === 0) {
+ logger.info(`Package ${packageKey} has no versions.`);
+ } else {
+ packageVersions.forEach(packageVersion => logger.info(JSON.stringify(packageVersion)));
+ }
+ }
+
public async createPackageVersion(
packageKey: string,
version: string | undefined,
diff --git a/tests/commands/configuration-management/config-version-list.spec.ts b/tests/commands/configuration-management/config-version-list.spec.ts
new file mode 100644
index 00000000..a0945faf
--- /dev/null
+++ b/tests/commands/configuration-management/config-version-list.spec.ts
@@ -0,0 +1,56 @@
+import { PackageVersionTransport } from "../../../src/commands/configuration-management/interfaces/package-version.interfaces";
+import { mockAxiosGet } from "../../utls/http-requests-mock";
+import { testContext } from "../../utls/test-context";
+import { loggingTestTransport } from "../../jest.setup";
+import {
+ PackageVersionCommandService
+} from "../../../src/commands/configuration-management/package-version-command.service";
+import { getJsonFromDownloadedFile } from "../../utls/fs-utils";
+
+describe("Package Version list", () => {
+ const buildPackageVersion = (packageKey: string, version: string, deployed: boolean): PackageVersionTransport => ({
+ packageKey,
+ historyId: `history-${version}`,
+ version,
+ changeDate: new Date("2024-01-15T10:30:00Z").toISOString(),
+ publishDate: new Date("2024-01-15T11:00:00Z").toISOString(),
+ publishMessage: `Release ${version}`,
+ deployed,
+ publishedBy: "user@example.com",
+ });
+
+ it("Should list package versions", async () => {
+ const packageKey = "test-package-key";
+ const packageVersions = [
+ buildPackageVersion(packageKey, "1.0.1", true),
+ buildPackageVersion(packageKey, "1.0.0", false),
+ ];
+ mockAxiosGet(`https://myTeam.celonis.cloud/pacman/api/core/packages/${packageKey}/versions`, packageVersions);
+
+ await new PackageVersionCommandService(testContext).listPackageVersions(packageKey, false);
+
+ expect(loggingTestTransport.logMessages).toHaveLength(2);
+ expect(JSON.parse(loggingTestTransport.logMessages[0].message)).toEqual(packageVersions[0]);
+ expect(JSON.parse(loggingTestTransport.logMessages[1].message)).toEqual(packageVersions[1]);
+ });
+
+ it("Should list branch versions and return them as JSON", async () => {
+ const branchPackageKey = "project-key@my-branch";
+ const packageVersions = [buildPackageVersion(branchPackageKey, "0.0.2", false)];
+ mockAxiosGet(`https://myTeam.celonis.cloud/pacman/api/core/packages/${branchPackageKey}/versions`, packageVersions);
+
+ await new PackageVersionCommandService(testContext).listPackageVersions(branchPackageKey, true);
+
+ expect(getJsonFromDownloadedFile()).toEqual(packageVersions);
+ });
+
+ it("Should report a package without versions", async () => {
+ const packageKey = "unpublished-package";
+ mockAxiosGet(`https://myTeam.celonis.cloud/pacman/api/core/packages/${packageKey}/versions`, []);
+
+ await new PackageVersionCommandService(testContext).listPackageVersions(packageKey, false);
+
+ expect(loggingTestTransport.logMessages).toHaveLength(1);
+ expect(loggingTestTransport.logMessages[0].message).toContain(`Package ${packageKey} has no versions.`);
+ });
+});
diff --git a/tests/integration/commands/configuration-management.spec.ts b/tests/integration/commands/configuration-management.spec.ts
index c5a48ec7..d19e74e0 100644
--- a/tests/integration/commands/configuration-management.spec.ts
+++ b/tests/integration/commands/configuration-management.spec.ts
@@ -69,6 +69,7 @@ describe("configuration-management command integration", () => {
mockPackageVersionCommandService = {
createPackageVersion: jest.fn().mockResolvedValue(undefined),
getPackageVersion: jest.fn().mockResolvedValue(undefined),
+ listPackageVersions: jest.fn().mockResolvedValue(undefined),
} as any;
mockSinglePackageImportService = {
@@ -981,6 +982,29 @@ describe("configuration-management command integration", () => {
});
});
+ describe("config versions list (listPackageVersions)", () => {
+ it("forwards the branch package key and --json", async () => {
+ await runCli([
+ "config", "versions", "list",
+ "--packageKey", "project-key@my-branch",
+ "--json",
+ ]);
+
+ expect(lastResult.exitCode).toBe(0);
+ expect(mockPackageVersionCommandService.listPackageVersions).toHaveBeenCalledWith(
+ "project-key@my-branch",
+ true
+ );
+ });
+
+ it("rejects when --packageKey is missing", async () => {
+ await runCli(["config", "versions", "list"]);
+
+ expectError("--packageKey ");
+ expect(mockPackageVersionCommandService.listPackageVersions).not.toHaveBeenCalled();
+ });
+ });
+
describe("config versions create (createPackageVersion)", () => {
it("rejects when both --packageVersion and --versionBumpOption PATCH are provided", async () => {
await runCli([