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
23 changes: 18 additions & 5 deletions src/cli/app/app-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ export default function setup() {
.addOption(
new Option(
'-i, --app-id <id>',
'Application name. If specified, -a and -A are ignored.'
'Application id. If specified, -n and -a are ignored.'
)
)
.addOption(
new Option('-a, --all', 'Delete all applications. Ignored with -i.')
new Option(
'-n, --app-name <name>',
'Application name. If specified, -a is ignored.'
)
)
.addOption(
new Option('-a, --all', 'Delete all applications. Ignored with -i or -n.')
)
.addOption(
new Option(
Expand Down Expand Up @@ -53,10 +59,17 @@ export default function setup() {
options,
command
);
// delete app by name
if (options.appId && (await getTokens(false, true, deploymentTypes))) {
// -i/--app-id or -n/--app-name
if (
(options.appId || options.appName) &&
(await getTokens(false, true, deploymentTypes))
) {
verboseMessage('Deleting application...');
const outcome = await deleteApplication(options.appId, options.deep);
const outcome = await deleteApplication(
options.appId,
options.appName,
options.deep
);
if (!outcome) process.exitCode = 1;
}
// -a/--all
Expand Down
8 changes: 7 additions & 1 deletion src/cli/app/app-describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ export default function setup() {

program
.description('Describe application.')
.addOption(new Option('-i, --app-id <id>', 'Application name.'))
.addOption(
new Option(
'-i, --app-id <id>',
'Application id. If specified, -n is ignored.'
)
)
.addOption(new Option('-n, --app-name <name>', 'Application name.'))
.addHelpText(
'after',
`Important Note:\n`['brightYellow'] +
Expand Down
20 changes: 15 additions & 5 deletions src/cli/app/app-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,27 @@ export default function setup() {
.description('Export applications.')
.addOption(
new Option(
'-i, --app-id <app-id>',
'-i, --app-id <id>',
'Application id. If specified, -n, -a, and -A are ignored.'
)
)
.addOption(
new Option(
'-n, --app-name <name>',
'Application name. If specified, -a and -A are ignored.'
)
)
.addOption(new Option('-f, --file <file>', 'Name of the export file.'))
.addOption(
new Option(
'-a, --all',
'Export all applications to a single file. Ignored with -i.'
'Export all applications to a single file. Ignored with -i or -n.'
)
)
.addOption(
new Option(
'-A, --all-separate',
'Export all applications to separate files (*.application.json) in the current directory. Ignored with -i or -a.'
'Export all applications to separate files (*.application.json) in the current directory. Ignored with -i, -n, or -a.'
)
)
.addOption(
Expand Down Expand Up @@ -75,11 +81,15 @@ export default function setup() {
options,
command
);
// export
if (options.appId && (await getTokens(false, true, deploymentTypes))) {
// -i/--app-id or -n/--app-name
if (
(options.appId || options.appName) &&
(await getTokens(false, true, deploymentTypes))
) {
verboseMessage('Exporting application...');
const outcome = await exportApplicationToFile(
options.appId,
options.appName,
options.file,
options.metadata,
{
Expand Down
19 changes: 14 additions & 5 deletions src/cli/app/app-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ export default function setup() {
.addOption(
new Option(
'-i, --app-id <id>',
'Application id. If specified, only one application is imported and the options -n, -a, and -A are ignored.'
)
)
.addOption(
new Option(
'-n, --app-name <name>',
'Application name. If specified, only one application is imported and the options -a and -A are ignored.'
)
)
.addOption(new Option('-f, --file <file>', 'Name of the file to import.'))
.addOption(
new Option(
'-a, --all',
'Import all applications from single file. Ignored with -i.'
'Import all applications from single file. Ignored with -i or -n.'
)
)
.addOption(
new Option(
'-A, --all-separate',
'Import all applications from separate files (*.app.json) in the current directory. Ignored with -i or -a.'
'Import all applications from separate files (*.app.json) in the current directory. Ignored with -i, -n, or -a.'
)
)
.addOption(
Expand Down Expand Up @@ -76,15 +82,18 @@ export default function setup() {
options,
command
);
// import by id
// -i/--app-id or -n/--app-name
if (
options.file &&
options.appId &&
(options.appId || options.appName) &&
(await getTokens(false, true, deploymentTypes))
) {
verboseMessage(`Importing application "${options.appId}"...`);
verboseMessage(
`Importing application "${options.appName ?? options.appId}"...`
);
const outcome = await importApplicationFromFile(
options.appId,
options.appName,
options.file,
{
deps: options.deps,
Expand Down
69 changes: 39 additions & 30 deletions src/ops/ApplicationOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ const {
} = frodo.utils;
const {
readApplications: _readApplications,
deleteApplication: _deleteApplication,
deleteApplicationByName: _deleteApplicationByName,
deleteApplications: _deleteApplications,
exportApplication: _exportApplication,
exportApplicationByName: _exportApplicationByName,
exportApplications: _exportApplications,
importApplication: _importApplication,
importApplicationByName: _importApplicationByName,
importFirstApplication: _importFirstApplication,
importApplications: _importApplications,
Expand Down Expand Up @@ -89,32 +91,35 @@ export async function listApplications(long = false): Promise<boolean> {

/**
* Delete application
* @param {string} applicationName application name
* @param {string | undefined} applicationId application id
* @param {string | undefined} applicationName application name
* @param {boolean} deep deep delete (include dependencies)
* @returns {Promise<boolean>} true if successful, false otherwise
*/
export async function deleteApplication(
applicationName: string,
applicationId: string | undefined,
applicationName: string | undefined,
deep: boolean
): Promise<boolean> {
const name = applicationName ?? applicationId;
let spinnerId: string;
try {
debugMessage(`cli.ApplicationOps.deleteApplication: begin`);
spinnerId = createProgressIndicator(
'indeterminate',
0,
`Deleting ${applicationName}...`
`Deleting ${name}...`
);
await _deleteApplicationByName(applicationName, deep);
stopProgressIndicator(spinnerId, `Deleted ${applicationName}`, 'success');
if (applicationId) {
await _deleteApplication(applicationId, deep);
} else {
await _deleteApplicationByName(applicationName, deep);
}
stopProgressIndicator(spinnerId, `Deleted ${name}`, 'success');
debugMessage(`cli.ApplicationOps.deleteApplication: end`);
return true;
} catch (error) {
stopProgressIndicator(
spinnerId,
`Error deleting ${applicationName}`,
'fail'
);
stopProgressIndicator(spinnerId, `Error deleting ${name}`, 'fail');
printError(error);
}
return false;
Expand Down Expand Up @@ -151,46 +156,47 @@ export async function deleteApplications(deep: boolean): Promise<boolean> {

/**
* Export application to file
* @param {string} applicationName application name
* @param {string | undefined} applicationId application id
* @param {string | undefined} applicationName application name
* @param {string} file file name
* @param {boolean} includeMeta true to include metadata, false otherwise. Default: true
* @param {ApplicationExportOptions} options export options
* @returns {Promise<boolean>} true if successful, false otherwise
*/
export async function exportApplicationToFile(
applicationName: string,
applicationId: string | undefined,
applicationName: string | undefined,
file: string,
includeMeta: boolean,
options: ApplicationExportOptions = { useStringArrays: true, deps: true }
) {
const name = applicationName ?? applicationId;
let spinnerId: string;
try {
debugMessage(`cli.ApplicationOps.exportApplicationToFile: begin`);
spinnerId = createProgressIndicator(
'indeterminate',
0,
`Exporting ${applicationName}...`
`Exporting ${name}...`
);
let fileName = getTypedFilename(applicationName, 'application');
let fileName = getTypedFilename(name, 'application');
if (file) {
fileName = file;
}
const filePath = getFilePath(fileName, true);
const exportData = await _exportApplicationByName(applicationName, options);
const exportData = applicationId
? await _exportApplication(applicationId, options)
: await _exportApplicationByName(applicationName, options);
saveJsonToFile(exportData, filePath, includeMeta);
stopProgressIndicator(
spinnerId,
`Exported ${applicationName} to ${filePath}.`,
`Exported ${name} to ${filePath}.`,
'success'
);
debugMessage(`cli.ApplicationOps.exportApplicationToFile: end`);
return true;
} catch (error) {
stopProgressIndicator(
spinnerId,
`Error exporting ${applicationName}`,
'fail'
);
stopProgressIndicator(spinnerId, `Error exporting ${name}`, 'fail');
printError(error);
}
return false;
Expand Down Expand Up @@ -317,17 +323,20 @@ export async function exportApplicationsToFiles(

/**
* Import application from file
* @param {string} applicationName client id
* @param {string | undefined} applicationId application id
* @param {string | undefined} applicationName application name
* @param {string} file file name
* @param {ApplicationImportOptions} options import options
* @returns {Promise<boolean>} true if successful, false otherwise
*/
export async function importApplicationFromFile(
applicationName: string,
applicationId: string | undefined,
applicationName: string | undefined,
file: string,
options: ApplicationImportOptions = { deps: true }
): Promise<boolean> {
let spinnerId: string;
const name = applicationName ?? applicationId;
try {
debugMessage(`cli.ApplicationOps.importApplicationFromFile: begin`);
spinnerId = createProgressIndicator(
Expand All @@ -337,16 +346,16 @@ export async function importApplicationFromFile(
);
const data = fs.readFileSync(getFilePath(file), 'utf8');
const fileData = JSON.parse(data);
await _importApplicationByName(applicationName, fileData, options);
stopProgressIndicator(spinnerId, `Imported ${applicationName}`, 'success');
if (applicationId) {
await _importApplication(applicationId, fileData, options);
} else {
await _importApplicationByName(applicationName, fileData, options);
}
stopProgressIndicator(spinnerId, `Imported ${name}`, 'success');
debugMessage(`cli.ApplicationOps.importApplicationFromFile: end`);
return true;
} catch (error) {
stopProgressIndicator(
spinnerId,
`Error importing ${applicationName}`,
'fail'
);
stopProgressIndicator(spinnerId, `Error importing ${name}`, 'fail');
printError(error);
}
return false;
Expand Down
6 changes: 5 additions & 1 deletion src/ops/PromoteOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,11 @@ async function deleteSwitch(
verboseMessage(
`Deleting Managed Application with name ${managedApplication.name}`
);
const outcome = await deleteApplication(managedApplication.name, true);
const outcome = await deleteApplication(
managedApplication._id,
managedApplication.name,
true
);
logmessages.push(`delete managedApplication ${deleteFilePath}`);
logmessages.push(`outcome: ${outcome}`);
logmessages.push(' ');
Expand Down
5 changes: 3 additions & 2 deletions test/client_cli/en/__snapshots__/app-delete.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ Arguments:
password Password.

Options:
-a, --all Delete all applications. Ignored with -i.
-a, --all Delete all applications. Ignored with -i or -n.
--curlirize Output all network calls in curl format.
-D, --directory <directory> Set the working directory.
--debug Debug output during command execution. If specified, may or may not produce additional output helpful for troubleshooting.
--flush-cache Flush token cache.
-h, --help Help
-i, --app-id <id> Application name. If specified, -a and -A are ignored.
-i, --app-id <id> Application id. If specified, -n and -a are ignored.
--idm-host <idm-host> IDM base URL, e.g.: https://cdk.idm.example.com/myidm. Use only if your IDM installation resides in a different domain and/or if the base path differs from the default "/openidm".
-k, --insecure Allow insecure connections when using SSL/TLS. Has no effect when using a network proxy for https (HTTPS_PROXY=http://<host>:<port>), in that case the proxy must provide this capability. (default: Don't allow insecure connections)
--login-client-id <client-id> Specify a custom OAuth2 client id to use a your own oauth2 client for IDM API calls in deployments of type "cloud" or "forgeops". Your custom client must be configured as a public client and allow the authorization code grant using the "openid fr:idm:*" scope. Use the "--redirect-uri" parameter if you have configured a custom redirect uri (default: "<host>/platform/appAuthHelperRedirect.html").
Expand All @@ -28,6 +28,7 @@ Options:
cloud: A ForgeRock Identity Cloud environment.
forgeops: A ForgeOps CDK or CDM deployment.
The detected or provided deployment type controls certain behavior like obtaining an Identity Management admin token or not and whether to export/import referenced email templates or how to walk through the tenant admin login flow of Identity Cloud and handle MFA (choices: "classic", "cloud", "forgeops")
-n, --app-name <name> Application name. If specified, -a is ignored.
--no-cache Disable token cache for this operation.
--no-deep No deep delete. This leaves orphaned configuration artifacts behind.
--passphrase <passphrase> The passphrase for the Amster private key if it is encrypted.
Expand Down
7 changes: 4 additions & 3 deletions test/client_cli/en/__snapshots__/app-export.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ Arguments:
password Password.

Options:
-a, --all Export all applications to a single file. Ignored with -i.
-A, --all-separate Export all applications to separate files (*.application.json) in the current directory. Ignored with -i or -a.
-a, --all Export all applications to a single file. Ignored with -i or -n.
-A, --all-separate Export all applications to separate files (*.application.json) in the current directory. Ignored with -i, -n, or -a.
--curlirize Output all network calls in curl format.
-D, --directory <directory> Set the working directory.
--debug Debug output during command execution. If specified, may or may not produce additional output helpful for troubleshooting.
-f, --file <file> Name of the export file.
--flush-cache Flush token cache.
-h, --help Help
-i, --app-id <app-id> Application name. If specified, -a and -A are ignored.
-i, --app-id <id> Application id. If specified, -n, -a, and -A are ignored.
--idm-host <idm-host> IDM base URL, e.g.: https://cdk.idm.example.com/myidm. Use only if your IDM installation resides in a different domain and/or if the base path differs from the default "/openidm".
-k, --insecure Allow insecure connections when using SSL/TLS. Has no effect when using a network proxy for https (HTTPS_PROXY=http://<host>:<port>), in that case the proxy must provide this capability. (default: Don't allow insecure connections)
--login-client-id <client-id> Specify a custom OAuth2 client id to use a your own oauth2 client for IDM API calls in deployments of type "cloud" or "forgeops". Your custom client must be configured as a public client and allow the authorization code grant using the "openid fr:idm:*" scope. Use the "--redirect-uri" parameter if you have configured a custom redirect uri (default: "<host>/platform/appAuthHelperRedirect.html").
Expand All @@ -30,6 +30,7 @@ Options:
cloud: A ForgeRock Identity Cloud environment.
forgeops: A ForgeOps CDK or CDM deployment.
The detected or provided deployment type controls certain behavior like obtaining an Identity Management admin token or not and whether to export/import referenced email templates or how to walk through the tenant admin login flow of Identity Cloud and handle MFA (choices: "classic", "cloud", "forgeops")
-n, --app-name <name> Application name. If specified, -a and -A are ignored.
-N, --no-metadata Does not include metadata in the export file.
--no-cache Disable token cache for this operation.
--no-deps Do not include any dependencies (scripts).
Expand Down
Loading
Loading