Skip to content

Commit

Permalink
feat: Prompt to install under broader conditions
Browse files Browse the repository at this point in the history
Prompt to install if a project satisfies all of:
* Has a supported language
* Has a supported framework
* Does not already have an appmap.yml
  • Loading branch information
kgilpin committed Jun 5, 2023
1 parent 1348e3b commit 689c254
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 47 deletions.
8 changes: 4 additions & 4 deletions src/actions/promptInstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { WorkspaceServices } from '../services/workspaceServices';
import * as vscode from 'vscode';
import { INSTALL_PROMPT, Telemetry } from '../telemetry';
import ExtensionState from '../configuration/extensionState';
import { hasSupportedFramework, isLanguageSupported } from '../workspace/projectMetadata';

export enum ButtonText {
Confirm = 'Open instructions',
Expand All @@ -23,10 +24,9 @@ const promptResponses: ReadonlyArray<vscode.MessageItem> = [
];

const meetsPromptCriteria = (project: ProjectStateServiceInstance): boolean =>
project.installable &&
!project.metadata.agentInstalled &&
project.metadata.language?.name === 'Ruby' &&
project.metadata.webFramework?.name === 'Rails';
isLanguageSupported(project.metadata) &&
hasSupportedFramework(project.metadata) &&
!project.metadata.agentInstalled;

export default async function promptInstall(
services: WorkspaceServices,
Expand Down
3 changes: 1 addition & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<AppMap
findByName(context, projectStates, appmapCollectionFile);
resetUsageState(context, extensionState);

if (!openedInstallGuide && !SignInManager.shouldShowSignIn())
promptInstall(workspaceServices, extensionState);
if (!openedInstallGuide) promptInstall(workspaceServices, extensionState);

vscode.env.onDidChangeTelemetryEnabled((enabled: boolean) => {
Telemetry.sendEvent(TELEMETRY_ENABLED, {
Expand Down
18 changes: 0 additions & 18 deletions src/services/projectStateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,24 +146,6 @@ export class ProjectStateServiceInstance implements WorkspaceServiceInstance {
return this._metadata as Readonly<ProjectMetadata>;
}

// Returns true if the project is installable and the agent has yet to be configured or
// AppMaps have yet to be recorded
get installable(): boolean {
return (
this.metadata.score !== undefined &&
this.metadata.score >= 2 &&
!(this.isAgentConfigured && this.hasRecordedAppMaps && this.metadata.analysisPerformed)
);
}

get supported(): boolean {
return (
(this.metadata.language?.score || 0) >= SCORE_VALUES.good &&
((this.metadata.webFramework?.score || 0) >= SCORE_VALUES.ok ||
(this.metadata.testFramework?.score || 0) >= SCORE_VALUES.ok)
);
}

get complete(): boolean {
return (
this.isAgentConfigured &&
Expand Down
42 changes: 19 additions & 23 deletions test/integration/actions/promptInstall.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import promptInstall, { ButtonText } from '../../../src/actions/promptInstall';
import ExtensionState from '../../../src/configuration/extensionState';
import { ProjectStateServiceInstance } from '../../../src/services/projectStateService';
import { ProjectA, unsafeCast } from '../util';
import Feature from '../../../src/workspace/feature';

const stubWorkspaceServices = (installable = true, language = 'Ruby', webFramework = 'Rails') =>
const stubWorkspaceServices = (language: Feature, webFramework?: Feature) =>
unsafeCast<WorkspaceServices>({
getService: () => sinon.stub(),
getServiceInstances: () =>
Expand All @@ -17,20 +18,26 @@ const stubWorkspaceServices = (installable = true, language = 'Ruby', webFramewo
folder: { name: path.basename(ProjectA), uri: vscode.Uri.parse(ProjectA), index: -1 },
metadata: {
agentInstalled: false,
language: { name: language },
webFramework: { name: webFramework },
language,
languages: [language],
webFramework,
},
installable,
},
]),
});

describe('promptInstall', () => {
const workspaceServices = stubWorkspaceServices();
const langAndFrameworkProject = stubWorkspaceServices(
{ name: 'Ruby', score: 2, text: 'GA language' },
{ name: 'Rails', score: 2, text: 'GA framework' }
);
const langOnlyProject = stubWorkspaceServices({ name: 'Ruby', score: 2, text: 'GA language' });

afterEach(() => sinon.restore());

context('in an installable project', () => {
const project = langAndFrameworkProject;

let hideInstallPrompt = false;
const extensionState = unsafeCast<ExtensionState>({
getHideInstallPrompt: () => hideInstallPrompt,
Expand All @@ -47,7 +54,7 @@ describe('promptInstall', () => {
it('prompts the user to install AppMap', async () => {
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage').resolves();

await promptInstall(workspaceServices, extensionState);
await promptInstall(project, extensionState);

assert(
showInformationMessage.calledWith(
Expand All @@ -61,7 +68,7 @@ describe('promptInstall', () => {
sinon.stub(vscode.window, 'showInformationMessage').resolves({ title: ButtonText.Confirm });
const executeCommand = sinon.stub(vscode.commands, 'executeCommand').resolves();

await promptInstall(workspaceServices, extensionState);
await promptInstall(project, extensionState);

assert(executeCommand.calledWith('appmap.openInstallGuide', 'project-picker'));
});
Expand All @@ -73,7 +80,7 @@ describe('promptInstall', () => {
const executeCommand = sinon.stub(vscode.commands, 'executeCommand').resolves();

for (let i = 0; i < 5; ++i) {
await promptInstall(workspaceServices, extensionState);
await promptInstall(project, extensionState);
assert(!executeCommand.called);
assert(showInformationMessage.calledOnce);
assert((extensionState.setHideInstallPrompt as sinon.SinonStub).calledOnce);
Expand All @@ -82,34 +89,23 @@ describe('promptInstall', () => {
});

context('when the user requests to never prompt in this project', () => {
const workspaceServices = stubWorkspaceServices();
const project = langAndFrameworkProject;
const extensionState = unsafeCast<ExtensionState>({ getHideInstallPrompt: () => true });

it('does not prompt', async () => {
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
await promptInstall(workspaceServices, extensionState);
await promptInstall(project, extensionState);
assert(!showInformationMessage.called);
});
});

context('when in an uninstallable project', () => {
const workspaceServices = stubWorkspaceServices(false);
const extensionState = unsafeCast<ExtensionState>({ getHideInstallPrompt: () => false });

it('does not prompt', async () => {
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
await promptInstall(workspaceServices, extensionState);
assert(!showInformationMessage.called);
});
});

context('when in an installable java project', () => {
const workspaceServices = stubWorkspaceServices(true, 'Java', 'Spring');
const project = langOnlyProject;
const extensionState = unsafeCast<ExtensionState>({ getHideInstallPrompt: () => false });

it('does not prompt', async () => {
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
await promptInstall(workspaceServices, extensionState);
await promptInstall(project, extensionState);
assert(!showInformationMessage.called);
});
});
Expand Down

0 comments on commit 689c254

Please sign in to comment.