ci-sf-plugin
Version:
Set of commands making CI and dev's life easier.
124 lines • 6.66 kB
JavaScript
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import * as os from 'os';
import * as util from 'util';
import * as childProcess from 'child_process';
import { readFileSync } from 'fs';
import { SfCommand, Flags, requiredOrgFlagWithDeprecations } from '@salesforce/sf-plugins-core';
import { Messages, SfError } from '@salesforce/core';
import { ux } from '@oclif/core';
// promisify child process
const execSync = util.promisify(childProcess.exec);
// Initialize Messages with the current plugin directory
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
// Load the specific messages for this file. Messages from @salesforce/command, @salesforce/core,
// or any library that is using the messages framework can also be loaded this way.
const messages = Messages.loadMessages('ci-sf-plugin', 'user.assign.profile');
export default class Profile extends SfCommand {
static description = messages.getMessage('commandDescription');
static examples = messages.getMessage('examples').split(os.EOL);
static flags = {
'target-org': requiredOrgFlagWithDeprecations,
// flag with a value (-n, --name=VALUE)
'profile-name': Flags.string({
char: 'n',
description: messages.getMessage('profilenameFlagDescription')
}),
'ci-config-file': Flags.file({
char: 'x',
default: 'ciconfig.json',
description: messages.getMessage('ciconfigfileFlagDescription')
})
};
// Set this to true if your command requires a project workspace; 'requiresProject' is false by default
static requiresProject = false;
async run() {
try {
const { flags } = await this.parse(Profile); // fetch needed flags
const targetOrgUsername = flags['target-org'].getUsername();
const profileNameFlag = flags['profile-name'];
const ciConfigFileFlag = flags['ci-config-file'];
ux.action.start(messages.getMessage('infoAssigningProfile', [targetOrgUsername]), 'in progress', { stdout: true });
// load configuration
let profile;
if (profileNameFlag) {
profile = profileNameFlag;
}
else {
const config = JSON.parse(readFileSync(ciConfigFileFlag, 'utf-8'));
if (!config.profile) {
throw new Error(`'profile' property is missing in the '${ciConfigFileFlag}' file, or is blank.`);
}
profile = config.profile;
}
const output = { stdout: [], stderr: [] };
// build the command, with --json to see details, get profile ID
const queryIdStr = `sf data query --query "SELECT Id FROM Profile WHERE Name = '${profile}'" --target-org ${targetOrgUsername} --json`;
const queryIdPromise = execSync(queryIdStr, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
const queryIdResultJson = JSON.parse((await queryIdPromise).stdout).result?.records[0];
process.stdout.write(`Profile '${profile}' has Id=${queryIdResultJson?.Id}.`);
const profileId = queryIdResultJson?.Id;
// create tmp user
const tmpUsername = `tmp-${Date.now()}_${targetOrgUsername}`;
const tmpUserCreateStr = `sf org create user --target-org ${targetOrgUsername} Username="${tmpUsername}" LastName="tmpUser" profileName="System Administrator"`;
const tmpUserCreatePromise = execSync(tmpUserCreateStr, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
tmpUserCreatePromise.child.stdout.on('data', (data) => {
if (data?.trim()) {
process.stdout.write(data);
}
});
tmpUserCreatePromise.child.stderr.on('data', (data) => {
if (data?.trim()) {
process.stderr.write(data.trim());
}
});
const tmpUserCreateOutput = await tmpUserCreatePromise;
output.stdout.push(tmpUserCreateOutput.stdout);
output.stderr.push(tmpUserCreateOutput.stderr);
// change profile of targetOrgUsername using tmpUsername
const updateProfileStr = `sf data update record --sobject User --where "Username=${targetOrgUsername}" --values "ProfileId='${profileId}'" --target-org ${tmpUsername}`;
const updateProfilePromise = execSync(updateProfileStr, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
updateProfilePromise.child.stdout.on('data', (data) => {
if (data?.trim()) {
process.stdout.write(data);
}
});
updateProfilePromise.child.stderr.on('data', (data) => {
if (data?.trim() && data.trim() !== 'Success') {
process.stderr.write(`Assign profile to the '${targetOrgUsername}' user: ${data.trim()}`);
}
});
const updateProfileOutput = await updateProfilePromise;
output.stdout.push(updateProfileOutput.stdout);
output.stderr.push(updateProfileOutput.stderr);
// deactivate our tmp user
const deactivateTmpUserStr = `sf data update record --sobject User --where "Username=${tmpUsername}" --values "IsActive=false" --target-org ${targetOrgUsername}`;
const deactivateTmpUserPromise = execSync(deactivateTmpUserStr, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
deactivateTmpUserPromise.child.stdout.on('data', (data) => {
if (data?.trim()) {
process.stdout.write(data);
}
});
deactivateTmpUserPromise.child.stderr.on('data', (data) => {
if (data?.trim() && data.trim() !== 'Success') {
process.stderr.write('Deactivate tmp user: ' + data.trim());
}
});
const deactivateTmpUserOutput = await deactivateTmpUserPromise;
output.stdout.push(deactivateTmpUserOutput.stdout);
output.stderr.push(deactivateTmpUserOutput.stderr);
ux.action.stop('done');
// Return an object
return { output };
}
catch (error) {
ux.action.stop('failed');
throw new SfError(messages.getMessage('errorAssignmentFailed', [JSON.stringify(error, null, 2)]));
}
}
}
//# sourceMappingURL=profile.js.map