Skip to content

Commit 48833ab

Browse files
pvicinuskuvia
andauthored
TA-5049 add content-cli options to list staging variables (#325)
Co-authored-by: Jing Sun <j.sun@celonis.com>
1 parent 4f19e2e commit 48833ab

8 files changed

Lines changed: 251 additions & 15 deletions

File tree

docs/user-guide/config-commands.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,17 @@ info: Config import report file: 9560f81f-f746-4117-83ee-dd1f614ad624.json
147147

148148
### Listing Package Variables
149149

150-
Package variables (with assignments) can be listed with the following command:
150+
Variables can be read for **versioned packages** or for the **unversioned** configuration of packages (identified by package key only). Use either the published flow (`--keysByVersion` / `--keysByVersionFile`) or the unversioned flow (`--packageKeys`); combining them is not supported and the command will fail.
151+
152+
**Output (console and `--json`).** For both flows, each package is represented the same way: `packageKey`, `variables` (definitions and values), and—**only for versioned packages**`version`. Without `--json`, each package is printed as one JSON object per line. With `--json`, the result is written to a file as a **JSON array** of those objects. For unversioned packages, `version` is simply omitted.
153+
154+
**Versioned packages**`config variables list` with `--keysByVersion` or `--keysByVersionFile`:
151155

152156
```bash
153157
content-cli config variables list -p <sourceProfile> --keysByVersion key1:version1 ... keyN:versionN
154158
```
155159

156-
The --keysByVersion option should specify a list of key :(colon) version pairs. Alternatively, a json file path containing a list of key and version pairs can be used. The PackageKeyAndVersionPair for the file should have the following form:
160+
The `--keysByVersion` option should specify a list of `key:version` pairs. Alternatively, pass a JSON file path with `--keysByVersionFile`. Each entry in the file should match:
157161

158162
```typescript
159163
export interface PackageKeyAndVersionPair {
@@ -162,7 +166,13 @@ export interface PackageKeyAndVersionPair {
162166
}
163167
```
164168

165-
Similar to the other listing commands, the --json option can be used for exporting (saving) the result as a json file.
169+
**Unpublished configuration**`config variables list` with `--packageKeys`:
170+
171+
```bash
172+
content-cli config variables list -p <profile> --packageKeys <packageKey> [<packageKey> ...]
173+
```
174+
175+
Use `--json` with either flow to export the array to a file (see **Output** above).
166176

167177
### Listing Assignments
168178

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Context } from "../../../core/command/cli-context";
2+
import { FatalError } from "../../../core/utils/logger";
3+
import { HttpClient } from "../../../core/http/http-client";
4+
import { StagingVariableManifestTransport } from "../interfaces/package-export.interfaces";
5+
6+
export class StagingPackageVariablesApi {
7+
private readonly httpClient: () => HttpClient;
8+
9+
constructor(context: Context) {
10+
this.httpClient = () => context.httpClient;
11+
}
12+
13+
public async findAllByPackageKeys(packageKeys: string[]): Promise<StagingVariableManifestTransport[]> {
14+
const path = `/pacman/api/core/staging/packages/variables/by-package-keys`;
15+
return await this.httpClient()
16+
.post(path, packageKeys)
17+
.catch(e => {
18+
throw new FatalError(`Problem listing staging variables for packages: ${e}`);
19+
});
20+
}
21+
}

src/commands/configuration-management/config-command.service.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,19 @@ export class ConfigCommandService {
3131
}
3232
}
3333

34-
public async listVariables(jsonResponse: boolean, keysByVersion: string[], keysByVersionFile: string): Promise<void> {
35-
if (jsonResponse) {
34+
public async listVariables(
35+
jsonResponse: boolean,
36+
keysByVersion: string[],
37+
keysByVersionFile: string,
38+
packageKeys: string[]
39+
): Promise<void> {
40+
if (packageKeys.length > 0) {
41+
if (jsonResponse) {
42+
await this.variableService.exportStagingVariables(packageKeys);
43+
} else {
44+
await this.variableService.listStagingVariables(packageKeys);
45+
}
46+
} else if (jsonResponse) {
3647
await this.variableService.exportVariables(keysByVersion, keysByVersionFile);
3748
} else {
3849
await this.variableService.listVariables(keysByVersion, keysByVersionFile);

src/commands/configuration-management/interfaces/package-export.interfaces.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ export interface VariableManifestTransport {
4949
variables?: VariableExportTransport[];
5050
}
5151

52+
export interface StagingVariableManifestTransport {
53+
packageKey: string;
54+
variables?: VariableExportTransport[];
55+
}
56+
5257
export interface PackageKeyAndVersionPair {
5358
packageKey: string;
5459
version: string;

src/commands/configuration-management/module.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ class Module extends IModule {
8787
.description("Commands related to variable configs");
8888

8989
variablesCommand.command("list")
90-
.description("Command to list versioned variables of packages")
90+
.description("List package variables: use --packageKeys for unversioned, or --keysByVersion / --keysByVersionFile for versioned packages")
9191
.option("--json", "Return response as json type", "")
92-
.option("--keysByVersion <keysByVersion...>", "Mapping of package keys and versions", "")
92+
.option("--packageKeys <packageKeys...>", "Package keys (unversioned variables only; mutually exclusive with versioned options)", [])
93+
.option("--keysByVersion <keysByVersion...>", "Mapping of package keys and versions", [])
9394
.option("--keysByVersionFile <keysByVersionFile>", "Package keys by version mappings file path.", "")
9495
.action(this.listVariables);
9596

@@ -203,7 +204,27 @@ class Module extends IModule {
203204
}
204205

205206
private async listVariables(context: Context, command: Command, options: OptionValues): Promise<void> {
206-
await new ConfigCommandService(context).listVariables(options.json, options.keysByVersion, options.keysByVersionFile);
207+
const hasStagingKeys = options.packageKeys.length > 0;
208+
const hasVersioned =
209+
options.keysByVersion.length > 0 || options.keysByVersionFile !== "";
210+
211+
if (hasStagingKeys && hasVersioned) {
212+
throw new Error(
213+
"Please provide either --packageKeys or --keysByVersion/--keysByVersionFile, but not both."
214+
);
215+
}
216+
if (!hasStagingKeys && !hasVersioned) {
217+
throw new Error(
218+
"Please provide --packageKeys for staging, or --keysByVersion / --keysByVersionFile for versioned packages."
219+
);
220+
}
221+
222+
await new ConfigCommandService(context).listVariables(
223+
options.json,
224+
options.keysByVersion,
225+
options.keysByVersionFile,
226+
options.packageKeys
227+
);
207228
}
208229

209230
private async listAssignments(context: Context, command: Command, options: OptionValues): Promise<void> {

src/commands/configuration-management/variable.service.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ import { Context } from "../../core/command/cli-context";
33
import { FatalError, logger } from "../../core/utils/logger";
44
import { StudioService } from "./studio.service";
55
import { FileService, fileService } from "../../core/utils/file-service";
6-
import { PackageKeyAndVersionPair, VariableManifestTransport } from "./interfaces/package-export.interfaces";
6+
import { PackageKeyAndVersionPair, StagingVariableManifestTransport, VariableManifestTransport } from "./interfaces/package-export.interfaces";
77
import { BatchImportExportApi } from "./api/batch-import-export-api";
88
import { URLSearchParams } from "url";
99
import { VariableAssignmentCandidatesApi } from "./api/variable-assignment-candidates-api";
10+
import { StagingPackageVariablesApi } from "./api/staging-package-variables-api";
1011

1112
export class VariableService {
1213

1314
private batchImportExportApi: BatchImportExportApi;
1415
private variableAssignmentCandidatesApi: VariableAssignmentCandidatesApi;
16+
private readonly stagingPackageVariablesApi: StagingPackageVariablesApi;
1517
private studioService: StudioService;
1618

1719
constructor(context: Context) {
1820
this.batchImportExportApi = new BatchImportExportApi(context);
1921
this.variableAssignmentCandidatesApi = new VariableAssignmentCandidatesApi(context);
22+
this.stagingPackageVariablesApi = new StagingPackageVariablesApi(context);
2023
this.studioService = new StudioService(context);
2124
}
2225

@@ -50,6 +53,24 @@ export class VariableService {
5053
this.exportToJson(variableManifests);
5154
}
5255

56+
public async listStagingVariables(packageKeys: string[]): Promise<void> {
57+
const byPackage = await this.fetchStagingVariablesByPackageKeys(packageKeys);
58+
byPackage.forEach(entry => {
59+
logger.info(JSON.stringify(entry));
60+
});
61+
}
62+
63+
public async exportStagingVariables(packageKeys: string[]): Promise<void> {
64+
const byPackage = await this.fetchStagingVariablesByPackageKeys(packageKeys);
65+
this.exportToJson(byPackage);
66+
}
67+
68+
private async fetchStagingVariablesByPackageKeys(
69+
packageKeys: string[]
70+
): Promise<StagingVariableManifestTransport[]> {
71+
return await this.stagingPackageVariablesApi.findAllByPackageKeys(packageKeys);
72+
}
73+
5374
private async getVersionedVariablesByKeyVersionPairs(keysByVersion: string[], keysByVersionFile: string): Promise<VariableManifestTransport[]> {
5475
const variablesExportRequest: PackageKeyAndVersionPair[] = await this.buildKeyVersionPairs(keysByVersion, keysByVersionFile);
5576

tests/commands/configuration-management/config-list-variables.spec.ts

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import * as fs from "fs";
33
import { parse } from "../../../src/core/utils/json";
44
import {
55
PackageKeyAndVersionPair,
6+
StagingVariableManifestTransport,
7+
VariableExportTransport,
68
VariableManifestTransport,
79
} from "../../../src/commands/configuration-management/interfaces/package-export.interfaces";
810
import { PackageManagerVariableType } from "../../../src/commands/studio/interfaces/package-manager.interfaces";
@@ -112,7 +114,7 @@ describe("Config listVariables", () => {
112114
})
113115

114116
it("Should list fixed variables for non-json response", async () => {
115-
await new ConfigCommandService(testContext).listVariables(false, ["key-1:1.0.0", "key-2:1.0.0", "key-3:1.0.0"], null);
117+
await new ConfigCommandService(testContext).listVariables(false, ["key-1:1.0.0", "key-2:1.0.0", "key-3:1.0.0"], "", []);
116118

117119
expect(loggingTestTransport.logMessages.length).toBe(3);
118120
expect(loggingTestTransport.logMessages[0].message).toContain(JSON.stringify(fixedVariableManifests[0]));
@@ -124,7 +126,7 @@ describe("Config listVariables", () => {
124126
})
125127

126128
it("Should export fixed variables for json response", async () => {
127-
await new ConfigCommandService(testContext).listVariables(true, ["key-1:1.0.0", "key-2:1.0.0", "key-3:1.0.0"], null);
129+
await new ConfigCommandService(testContext).listVariables(true, ["key-1:1.0.0", "key-2:1.0.0", "key-3:1.0.0"], "", []);
128130

129131
expect(loggingTestTransport.logMessages.length).toBe(1);
130132
expect(loggingTestTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage);
@@ -140,7 +142,7 @@ describe("Config listVariables", () => {
140142
(fs.existsSync as jest.Mock).mockReturnValue(true);
141143
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(packageKeyAndVersionPairs));
142144

143-
await new ConfigCommandService(testContext).listVariables(false, [], "key_version_mapping.json");
145+
await new ConfigCommandService(testContext).listVariables(false, [], "key_version_mapping.json", []);
144146

145147
expect(loggingTestTransport.logMessages.length).toBe(3);
146148
expect(loggingTestTransport.logMessages[0].message).toContain(JSON.stringify(fixedVariableManifests[0]));
@@ -155,7 +157,7 @@ describe("Config listVariables", () => {
155157
(fs.existsSync as jest.Mock).mockReturnValue(true);
156158
(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(packageKeyAndVersionPairs));
157159

158-
await new ConfigCommandService(testContext).listVariables(true, [], "key_version_mapping.json");
160+
await new ConfigCommandService(testContext).listVariables(true, [], "key_version_mapping.json", []);
159161

160162
expect(loggingTestTransport.logMessages.length).toBe(1);
161163
expect(loggingTestTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage);
@@ -169,9 +171,66 @@ describe("Config listVariables", () => {
169171

170172
it("Should throw error if no mapping and no file path is provided", async () => {
171173
try {
172-
await new ConfigCommandService(testContext).listVariables(true, [], "");
174+
await new ConfigCommandService(testContext).listVariables(true, [], "", []);
173175
} catch (e) {
174176
expect(e.message).toEqual("Please provide keysByVersion mappings or file path!");
175177
}
176178
})
177-
})
179+
180+
describe("staging variables via --packageKeys", () => {
181+
const stagingVariablesByPackageKeysBaseUrl =
182+
`${testContext.profile.team.replace(/\/$/, "")}/pacman/api/core/staging/packages/variables/by-package-keys`;
183+
184+
const stagingVarsPkgA: VariableExportTransport[] = [
185+
{ key: "DATA_POOL", type: "SINGLE_VALUE", value: "pool-id-1", metadata: {} },
186+
{ key: "OTHER", type: "CONNECTION", value: { connectionId: "c1" }, metadata: {} },
187+
];
188+
const stagingVarsPkgB: VariableExportTransport[] = [
189+
{ key: "DATA_POOL", type: "SINGLE_VALUE", value: "pool-id-2", metadata: {} },
190+
];
191+
192+
const batchResponse: StagingVariableManifestTransport[] = [
193+
{ packageKey: "pkg-a", variables: stagingVarsPkgA },
194+
{ packageKey: "pkg-b", variables: stagingVarsPkgB },
195+
];
196+
197+
const expectedPackageKeys = ["pkg-a", "pkg-b"];
198+
199+
it("Should list staging variables for non-json response", async () => {
200+
const url = stagingVariablesByPackageKeysBaseUrl;
201+
mockAxiosPost(url, batchResponse);
202+
203+
await new ConfigCommandService(testContext).listVariables(false, [], "", expectedPackageKeys);
204+
205+
expect(loggingTestTransport.logMessages.length).toBe(2);
206+
expect(loggingTestTransport.logMessages[0].message).toContain(JSON.stringify(batchResponse[0]));
207+
expect(loggingTestTransport.logMessages[1].message).toContain(JSON.stringify(batchResponse[1]));
208+
209+
const postBody = parse<string[]>(mockedPostRequestBodyByUrl.get(url));
210+
expect(postBody).toEqual(expectedPackageKeys);
211+
});
212+
213+
it("Should export staging variables for json response", async () => {
214+
const pkgAOnlyResponse: StagingVariableManifestTransport[] = [
215+
{ packageKey: "pkg-a", variables: stagingVarsPkgA },
216+
];
217+
const url = stagingVariablesByPackageKeysBaseUrl;
218+
mockAxiosPost(url, pkgAOnlyResponse);
219+
220+
await new ConfigCommandService(testContext).listVariables(true, [], "", ["pkg-a"]);
221+
222+
expect(loggingTestTransport.logMessages.length).toBe(1);
223+
expect(loggingTestTransport.logMessages[0].message).toContain(FileService.fileDownloadedMessage);
224+
225+
const expectedFileName = loggingTestTransport.logMessages[0].message.split(FileService.fileDownloadedMessage)[1];
226+
expect(mockWriteFileSync).toHaveBeenCalledWith(
227+
path.resolve(process.cwd(), expectedFileName),
228+
JSON.stringify(pkgAOnlyResponse),
229+
{encoding: "utf-8"}
230+
);
231+
232+
const postBody = parse<string[]>(mockedPostRequestBodyByUrl.get(url));
233+
expect(postBody).toEqual(["pkg-a"]);
234+
});
235+
});
236+
});

0 commit comments

Comments
 (0)