Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: core extension command log #5856

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 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
22 changes: 18 additions & 4 deletions packages/salesforcedx-utils-vscode/src/cli/commandExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Subscription } from 'rxjs/Subscription';

// Below two dependancies are not structured correcly for import unless require is used.
/* eslint-disable @typescript-eslint/no-var-requires */
import { CommandEventStream, CommandEventType } from '../commands';
import { Command } from './';
const cross_spawn = require('cross-spawn');
const kill = require('tree-kill');
Expand Down Expand Up @@ -155,28 +156,36 @@ export class CompositeCliCommandExecution implements CommandExecution {
}
});
}
this.processErrorSubject.subscribe(() => {
this.processErrorSubject.subscribe(e => {
if (timerSubscriber) {
timerSubscriber.unsubscribe();
}
CommandEventStream.getInstance().post({ type: CommandEventType.ERROR, error: `${e}` });
});

this.processExitSubject.subscribe(() => {
this.processExitSubject.subscribe(exitCode => {
if (timerSubscriber) {
timerSubscriber.unsubscribe();
}
if (exitCode !== undefined) {
CommandEventStream.getInstance().post({ type: CommandEventType.EXIT_CODE, exitCode });
}
});
}

public successfulExit() {
CommandEventStream.getInstance().post({ type: CommandEventType.EXIT_CODE, exitCode: 0 });
this.exitSubject.next(0);
}

public failureExit(e?: {}) {
if (e) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions
CommandEventStream.getInstance().post({ type: CommandEventType.ERROR, error: `${e}` });
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a safer way to do this without all the eslint bypasses?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll see what I can do.

// eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions
this.stderr.next(`${e}${os.EOL}`);
}
CommandEventStream.getInstance().post({ type: CommandEventType.EXIT_CODE, exitCode: 1 });
this.exitSubject.next(1);
}
}
Expand Down Expand Up @@ -209,16 +218,21 @@ export class CliCommandExecution implements CommandExecution {

// Process
this.processExitSubject = Observable.fromEvent(childProcess, 'exit');
this.processExitSubject.subscribe(() => {
this.processExitSubject.subscribe(exitCode => {
if (timerSubscriber) {
timerSubscriber.unsubscribe();
}
if (exitCode !== undefined) {
CommandEventStream.getInstance().post({ type: CommandEventType.EXIT_CODE, exitCode });
}
});
this.processErrorSubject = Observable.fromEvent(childProcess, 'error');
this.processErrorSubject.subscribe(() => {
this.processErrorSubject.subscribe(e => {
if (timerSubscriber) {
timerSubscriber.unsubscribe();
}
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
CommandEventStream.getInstance().post({ type: CommandEventType.ERROR, error: `${e}` });
});

// Output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { EventEmitter } from 'events';
import 'rxjs/add/observable/fromEvent';
import { Observable } from 'rxjs/Observable';
import { CommandEventStream, CommandEventType } from '../commands';
import { Command } from '.';
import { CancellationToken, CommandExecution } from './commandExecutor';

Expand Down Expand Up @@ -47,5 +48,14 @@ export class LocalCommandExecution implements CommandExecution {
this.cmdEmitter,
LocalCommandExecution.STDERR_EVENT
) ;

this.processExitSubject.subscribe(exitCode => {
if (exitCode !== undefined) {
CommandEventStream.getInstance().post({ type: CommandEventType.EXIT_CODE, exitCode });
}
});
this.processErrorSubject.subscribe(error => {
CommandEventStream.getInstance().post({ type: CommandEventType.ERROR, error: `${error}` });
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 vscode from 'vscode';

export enum CommandEventType {
START = 'start',
END = 'end',
EXIT_CODE = 'exitCode',
DATA = 'data',
ERROR = 'error'
}

export type CommandEventStart = {
type: CommandEventType.START;
commandId: string;
};

export type CommandEventEnd = {
type: CommandEventType.END;
commandId: string;
};

export type CommandEventExitCode = {
type: CommandEventType.EXIT_CODE;
exitCode: number;
};

export type CommandEventData = {
type: CommandEventType.DATA;
data: any;
};

export type CommandEventError = {
type: CommandEventType.ERROR;
error: string;
};

export type CommandEvent = CommandEventStart | CommandEventEnd | CommandEventExitCode | CommandEventData | CommandEventError;

export class CommandEventStream {
private static instance: CommandEventStream;
private readonly eventEmitter = new vscode.EventEmitter<CommandEvent>();
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be assigned in the constructor for testability?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TS complains somewhere about the member not being initialized if I do that, when I write the tests I'll see if I can refactor to make everything happy.


private constructor() {}

public static getInstance(): CommandEventStream {
if (!CommandEventStream.instance) {
CommandEventStream.instance = new CommandEventStream();
}
return CommandEventStream.instance;
}

public initialize(extensionContext: vscode.ExtensionContext) {
extensionContext.subscriptions.push(this.eventEmitter);
}

public readonly onCommandEvent: vscode.Event<CommandEvent> = this.eventEmitter.event;

public post(event: CommandEvent) {
this.eventEmitter.fire(event);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we wrap this in a try/catch and log, but not fail on the error if on occurs? It'd be good to avoid failing command execution due to monitoring code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. good call

}
}
1 change: 1 addition & 0 deletions packages/salesforcedx-utils-vscode/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

export { ChannelService } from './channelService';
export * from './commandEventStream';

import { NotificationService } from './notificationService';
export const notificationService = NotificationService.getInstance();
Expand Down
107 changes: 40 additions & 67 deletions packages/salesforcedx-vscode-core/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,117 +17,89 @@ export {
} from './auth/authParamsGatherer';
export { orgLoginAccessToken } from './auth/orgLoginAccessToken';
export {
DeviceCodeResponse,
OrgLoginWebContainerExecutor,
createOrgLoginWebExecutor, DeviceCodeResponse, orgLoginWeb, OrgLoginWebContainerExecutor,
OrgLoginWebDemoModeExecutor,
OrgLoginWebExecutor,
createOrgLoginWebExecutor,
orgLoginWeb
OrgLoginWebExecutor
} from './auth/orgLoginWeb';
export {
AuthDevHubParams,
AuthDevHubParamsGatherer,
OrgLoginWebDevHubContainerExecutor,
AuthDevHubParamsGatherer, createAuthDevHubExecutor,
orgLoginWebDevHub, OrgLoginWebDevHubContainerExecutor,
OrgLoginWebDevHubDemoModeExecutor,
OrgLoginWebDevHubExecutor,
createAuthDevHubExecutor,
orgLoginWebDevHub
OrgLoginWebDevHubExecutor
} from './auth/orgLoginWebDevHub';
export { OrgLogoutAll, orgLogoutAll, orgLogoutDefault } from './auth/orgLogout';
export { ConfigList, configList } from './configList';
export { ConfigSetExecutor, configSet } from './configSet';
export { configSet, ConfigSetExecutor } from './configSet';
export { dataQuery } from './dataQuery';
export {
DebuggerSessionDetachExecutor,
IdGatherer,
DebuggerSessionDetachExecutor, debuggerStop, IdGatherer,
IdSelection,
StopActiveDebuggerSessionExecutor,
debuggerStop
StopActiveDebuggerSessionExecutor
} from './debuggerStop';
export {
ConfirmationAndSourcePathGatherer,
DeleteSourceExecutor,
ManifestChecker,
deleteSource
ConfirmationAndSourcePathGatherer, deleteSource, DeleteSourceExecutor,
ManifestChecker
} from './deleteSource';
export { projectGenerateManifest } from './projectGenerateManifest';
export { DescribeMetadataExecutor, describeMetadata } from './describeMetadata';
export { ListMetadataExecutor, listMetadata } from './listMetadata';
export {
PackageInstallExecutor,
SelectInstallationKey,
SelectPackageID,
packageInstall
} from './packageInstall';
export {
RefreshSObjectsExecutor,
checkSObjectsAndRefresh,
refreshSObjects,
initSObjectDefinitions
} from './refreshSObjects';
export { renameLightningComponent } from './renameLightningComponent';
export { deployManifest } from './deployManifest';
export {
LibraryDeploySourcePathExecutor,
deploySourcePaths
deploySourcePaths, LibraryDeploySourcePathExecutor
} from './deploySourcePath';
export { sourceDiff, sourceFolderDiff, handleCacheResults } from './sourceDiff';
export { retrieveManifest } from './retrieveManifest';
export { retrieveComponent } from './retrieveMetadata';
export {
LibraryRetrieveSourcePathExecutor,
SourcePathChecker,
retrieveSourcePaths
} from './retrieveSourcePath';
export { describeMetadata, DescribeMetadataExecutor } from './describeMetadata';
export { listMetadata, ListMetadataExecutor } from './listMetadata';
export { openDocumentation } from './openDocumentation';
export { AliasGatherer, OrgCreateExecutor, orgCreate } from './orgCreate';
export { AliasGatherer, orgCreate, OrgCreateExecutor } from './orgCreate';
export { orgDelete } from './orgDelete';
export { OrgDisplay, orgDisplay } from './orgDisplay';
export { orgList } from './orgList';
export {
OrgOpenContainerExecutor,
OrgOpenExecutor,
getExecutor,
orgOpen
orgOpen, OrgOpenContainerExecutor,
OrgOpenExecutor
} from './orgOpen';
export {
ProjectDeployStartExecutor,
projectDeployStart
packageInstall, PackageInstallExecutor,
SelectInstallationKey,
SelectPackageID
} from './packageInstall';
export {
projectDeployStart, ProjectDeployStartExecutor
} from './projectDeployStart';
export {
PathExistsChecker,
ProjectNameAndPathAndTemplate,
ProjectTemplateItem,
PathExistsChecker, projectGenerateWithManifest, ProjectNameAndPathAndTemplate, projectTemplateEnum, ProjectTemplateItem,
SelectProjectFolder,
SelectProjectName,
SelectProjectTemplate,
projectGenerateWithManifest,
projectTemplateEnum,
sfProjectGenerate
SelectProjectTemplate, sfProjectGenerate
} from './projectGenerate';
export { projectGenerateManifest } from './projectGenerateManifest';
export {
ProjectRetrieveStartExecutor,
projectRetrieveStart
projectRetrieveStart, ProjectRetrieveStartExecutor
} from './projectRetrieveStart';
export {
checkSObjectsAndRefresh, initSObjectDefinitions, refreshSObjects, RefreshSObjectsExecutor
} from './refreshSObjects';
export { renameLightningComponent } from './renameLightningComponent';
export { retrieveManifest } from './retrieveManifest';
export { retrieveComponent } from './retrieveMetadata';
export {
LibraryRetrieveSourcePathExecutor, retrieveSourcePaths, SourcePathChecker
} from './retrieveSourcePath';
export {
viewAllChanges,
viewLocalChanges,
viewRemoteChanges
} from './source/viewChanges';
export { handleCacheResults, sourceDiff, sourceFolderDiff } from './sourceDiff';
export {
CreateDebugLevel,
CreateTraceFlag,
QueryTraceFlag,
QueryUser,
StartApexDebugLoggingExecutor,
QueryUser, startApexDebugLogging, StartApexDebugLoggingExecutor,
UpdateDebugLevelsExecutor,
UpdateTraceFlagsExecutor,
startApexDebugLogging
UpdateTraceFlagsExecutor
} from './startApexDebugLogging';
export {
StopApexDebugLoggingExecutor,
stopApexDebugLogging,
turnOffLogging
stopApexDebugLogging, StopApexDebugLoggingExecutor, turnOffLogging
} from './stopApexDebugLogging';
export { taskStop } from './taskStop';
export {
Expand All @@ -149,5 +121,6 @@ export {
visualforceGenerateComponent,
visualforceGeneratePage
} from './templates';
export { CommandLogEntry, getCommandLog, getLastCommandLogEntry, registerCommand } from './util';
import { DeveloperLogTraceFlag } from '../traceflag/developerLogTraceFlag';
export const developerLogTraceFlag = DeveloperLogTraceFlag.getInstance();
Loading
Loading