ci-sf-plugin
Version:
Set of commands making CI and dev's life easier.
106 lines • 5.12 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);
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', 'apex.execute');
export default class Execute 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)
'pre-push': Flags.boolean({
default: false,
description: messages.getMessage('prepushFlagDescription')
}),
'post-push': Flags.boolean({
default: false,
description: messages.getMessage('postpushFlagDescription')
}),
'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(Execute); // fetch needed flags
const targetOrgUsername = flags['target-org'].getUsername();
const prePushFlag = flags['pre-push'];
const postPushFlag = flags['post-push'];
const ciConfigFileFlag = flags['ci-config-file'];
ux.action.start(messages.getMessage('infoExecution', [targetOrgUsername]), 'in progress', { stdout: true });
// load configuration
let apexScripts = [];
if (prePushFlag === postPushFlag) {
throw new Error(`Specify either 'prepush' or 'postpush' flag, not both.`);
}
else {
const propertyKey = prePushFlag ? 'apexPrePush' : 'apexPostPush';
const config = JSON.parse(readFileSync(ciConfigFileFlag, 'utf-8'));
if (!config[propertyKey] || !Array.isArray(config[propertyKey])) {
throw new Error(`'${propertyKey}' property is missing in the '${ciConfigFileFlag}' file, or is not an array.`);
}
apexScripts = config[propertyKey];
}
const output = { stdout: [], stderr: [] };
let errorMessage = '';
for (const apexScript of apexScripts) {
// build the command, without --json to see details
const commandStr = `sf apex run --file ${apexScript} --target-org ${targetOrgUsername}`;
// execute and print output
const commandPromise = execSync(commandStr, { encoding: 'utf8', maxBuffer: 1024 * 1024 });
commandPromise.child.stdout.on('data', (data) => {
if (data?.trim()) {
const dataOutput = [];
data.trim().split('\n').forEach(line => {
if (line.startsWith('Error')) {
errorMessage += line + '\n'; // make this task fail
}
if (!line.includes('|HEAP_ALLOCATE|')) { // filter useful info
dataOutput.push(line);
}
});
process.stdout.write(dataOutput.join('\n')); // prints simplified SF console log
}
});
commandPromise.child.stderr.on('data', (data) => {
if (data?.trim()) {
// nothing to do
}
});
const { stdout, stderr } = await commandPromise;
output.stdout.push(stdout);
output.stderr.push(stderr);
}
if (errorMessage) { // abort task based on stdout of anonymous apex above
throw new Error(errorMessage);
}
ux.action.stop('done');
// Return an object
return { output };
}
catch (error) {
ux.action.stop('failed');
throw new SfError(messages.getMessage('errorExecutionFailed', [JSON.stringify(error, null, 2)]));
}
}
}
//# sourceMappingURL=execute.js.map