Skip to content
Open
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
5 changes: 5 additions & 0 deletions docs/user-guide/t2tc-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ content-cli t2tc package export -p <sourceProfile> --packageKeys key1 ... keyN
The `--keysByVersion` option can be used to export packages by specific version. You can specify multiple packages with version separated by spaces, in the format of 'packageKey.version'.
The `--withDependencies` option can be used to also export dependencies of the given packages.
The `--unzip` option can be used to unzip the exported packages into the current working directory.
The `--staging` option exports the current staging state of the given `--packageKeys` instead of their latest deployed version. Branch package keys (`<projectKey>@<branchKey>`) are supported. Staging packages appear as `<packageKey>_staging.zip`, use `staging` as their version in `manifest.json` and `variables.json`, and their staging variable values are exported. With `--withDependencies`, dependencies are exported at the published versions the staging configuration references. `--staging` cannot be combined with `--keysByVersion`.

```bash
content-cli t2tc package export -p <sourceProfile> --packageKeys projectKey@branchKey --staging --withDependencies
```

Depending on the `--unzip` option used, a zip file, or a directory containing the exported packages, will be created in the current working directory containing:

Expand Down
10 changes: 10 additions & 0 deletions src/commands/t2tc/api/t2tc-package-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ export class T2tcPackageApi {
});
}

public async exportStagingPackages(packageKeys: string[], withDependencies: boolean): Promise<Buffer> {
const queryParams = new URLSearchParams();
packageKeys.forEach(packageKey => queryParams.append("packageKeys", packageKey));
queryParams.set("withDependencies", withDependencies.toString());

return this.httpClient().getFile(`/package-manager/api/core/staging/packages/export/batch?${queryParams.toString()}`).catch(e => {
throw new FatalError(`Problem exporting staging packages: ${e}`);
});
}

public async exportPackagesByVersions(packageKeysWithVersion: string[], withDependencies: boolean): Promise<Buffer> {
const queryParams = new URLSearchParams();
packageKeysWithVersion.forEach(packageKeyByVersion => queryParams.append("packageKeysWithVersion", packageKeyByVersion));
Expand Down
3 changes: 2 additions & 1 deletion src/commands/t2tc/batch-export-import.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export enum BatchExportImportConstants {
ZIP_EXTENSION = ".zip",
JSON_EXTENSION = ".json",
NODES_FOLDER_NAME = "nodes/",
SCENARIO_NODE = "SCENARIO"
SCENARIO_NODE = "SCENARIO",
STAGING_VERSION = "staging"
}
6 changes: 5 additions & 1 deletion src/commands/t2tc/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Module extends IModule {
.option("--unzip", "Unzip the exported file", "")
.option("--gitProfile <gitProfile>", "Git profile which you want to use for the Git operations")
.option("--gitBranch <gitBranch>", "Git branch in which you want to push the exported file")
.option("--staging", "Export the staging state of the given --packageKeys (including branch packages) instead of the latest deployed version", false)
.action(this.batchExportPackages);

t2tcPackageCommand.command("import")
Expand Down Expand Up @@ -81,8 +82,11 @@ class Module extends IModule {
if (options.gitProfile && !options.gitBranch) {
throw new Error("Please specify a branch using --gitBranch when using a Git profile.");
}
if (options.staging && options.keysByVersion) {
throw new Error("Staging parameter is only supported with --packageKeys, not --keysByVersion.");
}
options.withDependencies = options.withDependencies ?? false;
await new T2tcCommandService(context).batchExportPackages(options.packageKeys, options.keysByVersion, options.withDependencies, options.gitBranch, options.unzip);
await new T2tcCommandService(context).batchExportPackages(options.packageKeys, options.keysByVersion, options.withDependencies, options.gitBranch, options.unzip, options.staging);
}

private async batchImportPackages(context: Context, command: Command, options: OptionValues): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/t2tc/t2tc-command.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export class T2tcCommandService {
}
}

public batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean): Promise<void> {
return this.t2tcPackageService.batchExportPackages(packageKeys, packageKeysByVersion, withDependencies, gitBranch, unzip);
public batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean, staging: boolean = false): Promise<void> {
return this.t2tcPackageService.batchExportPackages(packageKeys, packageKeysByVersion, withDependencies, gitBranch, unzip, staging);
}

public batchImportPackages(file: string, directory: string, overwrite: boolean, gitBranch: string, performValidation: boolean = false): Promise<void> {
Expand Down
32 changes: 28 additions & 4 deletions src/commands/t2tc/t2tc-package.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { parse, stringify } from "../../core/utils/json";
import { PackageApi } from "../studio/api/package-api";
import { T2tcPackageApi } from "./api/t2tc-package-api";
import { VariableApi } from "../configuration-management/api/variable-api";
import { StagingPackageVariablesApi } from "../configuration-management/api/staging-package-variables-api";
import { fixConnectionVariables } from "../configuration-management/connection-variable.helper";
import { StudioService } from "./studio.service";
import { GitService } from "../../core/git-profile/git/git.service";
Expand All @@ -26,6 +27,7 @@ export class T2tcPackageService {

private t2tcPackageApi: T2tcPackageApi;
private variableApi: VariableApi;
private stagingPackageVariablesApi: StagingPackageVariablesApi;

private studioPackageApi: PackageApi;
private studioService: StudioService;
Expand All @@ -35,6 +37,7 @@ export class T2tcPackageService {
constructor(context: Context) {
this.t2tcPackageApi = new T2tcPackageApi(context);
this.variableApi = new VariableApi(context);
this.stagingPackageVariablesApi = new StagingPackageVariablesApi(context);

this.studioPackageApi = new PackageApi(context);
this.studioService = new StudioService(context);
Expand Down Expand Up @@ -72,9 +75,11 @@ export class T2tcPackageService {
});
}

public async batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean): Promise<void> {
public async batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean, staging: boolean = false): Promise<void> {
let exportedPackagesData: Buffer;
if (packageKeys) {
if (staging) {
exportedPackagesData = await this.t2tcPackageApi.exportStagingPackages(packageKeys, withDependencies);
} else if (packageKeys) {
exportedPackagesData = await this.t2tcPackageApi.exportPackages(packageKeys, withDependencies);
} else {
exportedPackagesData = await this.t2tcPackageApi.exportPackagesByVersions(packageKeysByVersion, withDependencies);
Expand Down Expand Up @@ -184,18 +189,37 @@ export class T2tcPackageService {
return versionsByPackageKey;
}

private getVersionedVariablesForPackagesWithKeys(versionsByPackageKey: Map<string, string[]>): Promise<VariableManifestTransport[]> {
private async getVersionedVariablesForPackagesWithKeys(versionsByPackageKey: Map<string, string[]>): Promise<VariableManifestTransport[]> {
const variableExportRequest: PackageKeyAndVersionPair[] = [];
const stagingPackageKeys: string[] = [];
versionsByPackageKey?.forEach((versions, key) => {
versions?.forEach(version => {
if (version === BatchExportImportConstants.STAGING_VERSION) {
stagingPackageKeys.push(key);
return;
}
variableExportRequest.push({
packageKey: key,
version: version,
})
})
});

return this.variableApi.findVariablesWithValuesByPackageKeysAndVersion(variableExportRequest)
const versionedVariables = await this.variableApi.findVariablesWithValuesByPackageKeysAndVersion(variableExportRequest);
const stagingVariables = stagingPackageKeys.length
? await this.getStagingVariablesForPackagesWithKeys(stagingPackageKeys)
: [];

return [...versionedVariables, ...stagingVariables];
}

private async getStagingVariablesForPackagesWithKeys(packageKeys: string[]): Promise<VariableManifestTransport[]> {
const stagingVariables = await this.stagingPackageVariablesApi.findAllByPackageKeys(packageKeys);
return stagingVariables.map(stagingVariable => ({
packageKey: stagingVariable.packageKey,
version: BatchExportImportConstants.STAGING_VERSION,
variables: stagingVariable.variables ?? [],
}));
}

private buildBodyForImport(configs: AdmZip, sourcePath: string, variablesManifests: VariableManifestTransport[]): FormData {
Expand Down
33 changes: 33 additions & 0 deletions tests/commands/t2tc/module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,39 @@ describe("T2TC Module", () => {
undefined,
false,
undefined,
true,
undefined
);
});

it("throws when --staging is combined with --keysByVersion", async () => {
const options: OptionValues = {
keysByVersion: ["package1.1.0.0"],
staging: true,
};

await expect(
(module as any).batchExportPackages(testContext, mockCommand, options)
).rejects.toThrow("Staging parameter is only supported with --packageKeys, not --keysByVersion.");

expect(mockT2tcCommandService.batchExportPackages).not.toHaveBeenCalled();
});

it("delegates to T2tcCommandService with staging enabled", async () => {
const options: OptionValues = {
packageKeys: ["project@my-branch"],
withDependencies: true,
staging: true,
};

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

expect(mockT2tcCommandService.batchExportPackages).toHaveBeenCalledWith(
["project@my-branch"],
undefined,
true,
undefined,
undefined,
true
);
});
Expand Down
48 changes: 47 additions & 1 deletion tests/commands/t2tc/t2tc-package-export.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1210,4 +1210,50 @@ describe("Config export", () => {

expect(getDownloadedFileName()).not.toBeNull();
})
})
it("Should export staging packages from the staging endpoint with staging variables", async () => {
const manifest: PackageManifestTransport[] = [];
manifest.push(ConfigUtils.buildManifestForKeyAndFlavorAndVersion("project@my-branch", "TEST", null, {
[BatchExportImportConstants.STAGING_VERSION]: [],
} as unknown as Map<string, DependencyTransport[]>));
manifest.push(ConfigUtils.buildManifestForKeyAndFlavorAndVersion("dependency-key", "TEST", "1.0.0", {
"1.0.0": [],
} as unknown as Map<string, DependencyTransport[]>));
const exportedPackagesZip = ConfigUtils.buildBatchExportZip(manifest, []);

const stagingVariable = {
key: "staging-variable",
type: PackageManagerVariableType.PLAIN_TEXT,
value: "staging-value",
metadata: {},
};
const versionedVariables: VariableManifestTransport[] = [{
packageKey: "dependency-key",
version: "1.0.0",
variables: [],
}];

mockAxiosGet("https://myTeam.celonis.cloud/package-manager/api/core/staging/packages/export/batch?packageKeys=project%40my-branch&withDependencies=true", exportedPackagesZip.toBuffer());
mockAxiosPost("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments", versionedVariables);
mockAxiosPost("https://myTeam.celonis.cloud/pacman/api/core/staging/packages/variables/by-package-keys", [{
packageKey: "project@my-branch",
variables: [stagingVariable],
}]);

await new T2tcCommandService(testContext).batchExportPackages(["project@my-branch"], undefined, true, null, null, true);

const versionedVariablesRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/package-manager/api/core/packages/export/batch/variables-with-assignments"));
expect(versionedVariablesRequest).toEqual([{packageKey: "dependency-key", version: "1.0.0"}]);

const stagingVariablesRequest = parse(mockedPostRequestBodyByUrl.get("https://myTeam.celonis.cloud/pacman/api/core/staging/packages/variables/by-package-keys"));
expect(stagingVariablesRequest).toEqual(["project@my-branch"]);

const actualZip = new AdmZip(getDownloadedFileName());
const exportedVariables: VariableManifestTransport[] = parse(actualZip.getEntry(BatchExportImportConstants.VARIABLES_FILE_NAME).getData().toString());
expect(exportedVariables).toContainEqual({
packageKey: "project@my-branch",
version: BatchExportImportConstants.STAGING_VERSION,
variables: [stagingVariable],
});
expect(exportedVariables).toContainEqual(versionedVariables[0]);
})
})
Loading