Skip to content
Merged
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
7 changes: 7 additions & 0 deletions messages/flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# flags.result-format.summary

Format of the test results.

# flags.code-coverage.summary

Retrieve code coverage results.
8 changes: 0 additions & 8 deletions messages/gettest.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ Provide a test run ID to display test results for an enqueued or completed async

ID of the test run.

# flags.result-format.summary

Format of the results.

# flags.code-coverage.summary

Retrieve code coverage results.

# flags.output-dir.summary

Directory in which to store test result files.
Expand Down
40 changes: 0 additions & 40 deletions messages/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,43 +21,3 @@ To fetch a specific log from your org, obtain the ID from this command's output,
# noDebugLogsFound

No debug logs found in org

# appColHeader
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a message for table headers seemed silly--we don't normally do that


APPLICATION

# durationColHeader

DURATION (MS)

# idColHeader

ID

# locationColHeader

LOCATION

# sizeColHeader

SIZE (B)

# userColHeader

LOG USER

# operationColHeader

OPERATION

# requestColHeader

REQUEST

# timeColHeader

START TIME

# statusColHeader

STATUS
4 changes: 0 additions & 4 deletions messages/runtest.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ NOTE: The testRunCoverage value (JSON and JUnit result formats) is a percentage

<%= config.bin %> <%= command.id %> --test-level RunLocalTests --output-dir <path to outputdir> --target-org me@my.org

# flags.result-format.summary

Format of the test results.

# flags.class-names.summary

Apex test class names to run; default is all classes.
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@
"@salesforce/core": "^7.4.1",
"@salesforce/kit": "^3.1.6",
"@salesforce/sf-plugins-core": "^11.1.0",
"chalk": "^5.3.0",
"color-convert": "^2.0.1",
"color-name": "^2.0.0"
"ansis": "^3.2.0"
},
"devDependencies": {
"@oclif/plugin-command-snapshot": "^5.2.2",
"@salesforce/cli-plugins-testkit": "^5.3.14",
"@salesforce/dev-scripts": "^10.1.1",
"@salesforce/plugin-command-reference": "^3.1.2",
"@types/color-convert": "^2.0.3",
"eslint-plugin-sf-plugin": "^1.18.5",
"oclif": "^4.12.1",
"ts-node": "^10.9.2",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/apex/get/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
SfCommand,
} from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import { colorLogs } from '../../../utils.js';
import { colorLogs } from '../../../logColorize.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'get');
Expand Down
18 changes: 3 additions & 15 deletions src/commands/apex/get/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import { RunResult, TestReporter } from '../../../reporters/index.js';
import { resultFormat } from '../../../utils.js';
import { codeCoverageFlag, resultFormatFlag } from '../../../flags.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'gettest');
Expand All @@ -40,26 +40,14 @@ export default class Test extends SfCommand<RunResult> {
startsWith: '707',
length: 'both',
}),
'code-coverage': Flags.boolean({
aliases: ['codecoverage'],
deprecateAliases: true,
char: 'c',
summary: messages.getMessage('flags.code-coverage.summary'),
}),
'code-coverage': codeCoverageFlag,
'output-dir': Flags.directory({
aliases: ['outputdir', 'output-directory'],
deprecateAliases: true,
char: 'd',
summary: messages.getMessage('flags.output-dir.summary'),
}),
'result-format': Flags.string({
deprecateAliases: true,
aliases: ['resultformat'],
char: 'r',
summary: messages.getMessage('flags.result-format.summary'),
options: resultFormat,
default: 'human',
}),
'result-format': resultFormatFlag,
};

public async run(): Promise<RunResult> {
Expand Down
75 changes: 30 additions & 45 deletions src/commands/apex/list/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'list');

export type LogListResult = LogRecord[];
type LogForTable = Omit<LogRecord, 'DurationMilliseconds' | 'User'> & { DurationMilliseconds: string; User: string };

export default class Log extends SfCommand<LogListResult> {
public static readonly summary = messages.getMessage('summary');
Expand All @@ -35,61 +36,45 @@ export default class Log extends SfCommand<LogListResult> {
public async run(): Promise<LogListResult> {
const { flags } = await this.parse(Log);

const conn = flags['target-org'].getConnection(flags['api-version']);
const logService = new LogService(conn);
const logRecords = await logService.getLogRecords();
const logService = new LogService(flags['target-org'].getConnection(flags['api-version']));
const logRecords = (await logService.getLogRecords()).map(formatStartTime);

if (logRecords.length === 0) {
this.log(messages.getMessage('noDebugLogsFound'));
return [];
}

logRecords.map((logRecord) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was doing mutation on the records. You'll see UT that were relying on that side effect to pass.

logRecord.StartTime = this.formatTime(logRecord.StartTime);
});

if (!flags.json) {
// while not required to prevent table output, save a few iterations if only printing json
const cleanLogs = logRecords.map((logRecord) => ({
app: logRecord.Application,
duration: String(logRecord.DurationMilliseconds),
id: logRecord.Id,
location: logRecord.Location,
size: String(logRecord.LogLength),
user: logRecord.LogUser.Name,
operation: logRecord.Operation,
request: logRecord.Request,
time: logRecord.StartTime,
status: logRecord.Status,
}));

this.table(
cleanLogs,
{
app: { header: messages.getMessage('appColHeader') },
duration: { header: messages.getMessage('durationColHeader') },
id: { header: messages.getMessage('idColHeader') },
location: { header: messages.getMessage('locationColHeader') },
size: { header: messages.getMessage('sizeColHeader') },
user: { header: messages.getMessage('userColHeader') },
operation: { header: messages.getMessage('operationColHeader') },
request: { header: messages.getMessage('requestColHeader') },
time: { header: messages.getMessage('timeColHeader') },
status: { header: messages.getMessage('statusColHeader') },
},
{ 'no-truncate': true }
);
this.table(logRecords.map(formatForTable), tableHeaders, { 'no-truncate': true });
}

return logRecords;
}

// eslint-disable-next-line class-methods-use-this
private formatTime(time: string): string {
const milliIndex = time.indexOf('.');
if (milliIndex !== -1) {
return time.substring(0, milliIndex) + time.substring(milliIndex + 4);
}
return time;
}
}

const formatForTable = (logRecord: LogRecord): LogForTable => ({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's really only 2 fields that needed transorming. The rest can use the name the server uses

...logRecord,
DurationMilliseconds: String(logRecord.DurationMilliseconds),
User: logRecord.LogUser.Name,
});

export const formatStartTime = (lr: LogRecord): LogRecord => ({ ...lr, StartTime: formatTime(lr.StartTime) });

const formatTime = (time: string): string => {
const msIndex = time.indexOf('.');
return msIndex !== -1 ? time.substring(0, msIndex) + time.substring(msIndex + 4) : time;
};

const tableHeaders = {
Application: { header: 'Application' },
DurationMilliseconds: { header: 'Duration (ms)' },
Id: { header: 'Id' },
Location: { header: 'Location' },
LogLength: { header: 'Size (B)' },
User: { header: 'Log User' },
Operation: { header: 'Operation' },
Request: { header: 'Request' },
StartTime: { header: 'Start Time' },
Status: { header: 'Status' },
};
18 changes: 3 additions & 15 deletions src/commands/apex/run/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { Messages, SfError } from '@salesforce/core';
import { Duration } from '@salesforce/kit';
import { RunResult, TestReporter } from '../../../reporters/index.js';
import { resultFormat } from '../../../utils.js';
import { codeCoverageFlag, resultFormatFlag } from '../../../flags.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'runtest');
Expand All @@ -37,12 +37,7 @@ export default class Test extends SfCommand<RunCommandResult> {
'target-org': requiredOrgFlagWithDeprecations,
'api-version': orgApiVersionFlagWithDeprecations,
loglevel,
'code-coverage': Flags.boolean({
aliases: ['codecoverage'],
deprecateAliases: true,
char: 'c',
summary: messages.getMessage('flags.code-coverage.summary'),
}),
'code-coverage': codeCoverageFlag,
'output-dir': Flags.directory({
aliases: ['outputdir', 'output-directory'],
deprecateAliases: true,
Expand All @@ -65,14 +60,7 @@ export default class Test extends SfCommand<RunCommandResult> {
description: messages.getMessage('flags.class-names.description'),
exclusive: exclusiveTestSpecifiers.filter((specifier) => specifier !== 'class-names'),
}),
'result-format': Flags.string({
deprecateAliases: true,
aliases: ['resultformat'],
char: 'r',
summary: messages.getMessage('flags.result-format.summary'),
options: resultFormat,
default: 'human',
}),
'result-format': resultFormatFlag,
'suite-names': arrayWithDeprecation({
deprecateAliases: true,
aliases: ['suitenames'],
Expand Down
7 changes: 4 additions & 3 deletions src/commands/apex/tail/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
loglevel,
} from '@salesforce/sf-plugins-core';
import { Connection, Messages } from '@salesforce/core';
import { colorizeLog } from '../../../legacyColorization.js';
import { colorLogs } from '../../../logColorize.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'tail');
Expand Down Expand Up @@ -66,10 +66,11 @@ export default class Log extends SfCommand<void> {
this.log(messages.getMessage('finishedTailing'));
}

// the colorize function used to be async, but not isn't. Preserving the public method signature
// eslint-disable-next-line @typescript-eslint/require-await
public async logTailer(fullLog: string): Promise<void> {
if (fullLog) {
const output = this.color ? await colorizeLog(fullLog) : fullLog;
this.log(output);
this.log(this.color ? colorLogs(fullLog) : fullLog);
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2023, 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 { Messages } from '@salesforce/core';
import { Flags } from '@salesforce/sf-plugins-core';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-apex', 'flags');

export const resultFormatFlag = Flags.string({
deprecateAliases: true,
aliases: ['resultformat'],
char: 'r',
summary: messages.getMessage('flags.result-format.summary'),
options: ['human', 'tap', 'junit', 'json'] as const,
default: 'human',
});

export const codeCoverageFlag = Flags.boolean({
aliases: ['codecoverage'],
deprecateAliases: true,
char: 'c',
summary: messages.getMessage('flags.code-coverage.summary'),
});
Loading