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

OpenShift Toolkit extension recommendation #892

Merged
merged 5 commits into from
Mar 2, 2023
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
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@
"type": "boolean",
"default": false,
"description": "Enforces alphabetical ordering of keys in mappings when set to true"
},
"yaml.recommendations.show": {
"type": "boolean",
"default": "true",
"description": "Suggest additional extensions based on YAML usage."
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { getConflictingExtensions, showUninstallConflictsNotification } from './
import { TelemetryErrorHandler, TelemetryOutputChannel } from './telemetry';
import { TextDecoder } from 'util';
import { createJSONSchemaStatusBarItem } from './schema-status-bar-item';
import { initializeRecommendation } from './recommendation';

export interface ISchemaAssociations {
[pattern: string]: string[];
Expand Down Expand Up @@ -206,6 +207,8 @@ export function startClient(
client.onNotification(SchemaSelectionRequests.schemaStoreInitialized, () => {
createJSONSchemaStatusBarItem(context, client);
});

initializeRecommendation(context);
})
.catch((err) => {
sendStartupTelemetryEvent(runtime.telemetry, false, err);
Expand Down
12 changes: 12 additions & 0 deletions src/recommendation/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

export interface IHandler {
handle(extName: string, message: string): Promise<void>;

canRecommendExtension(extName: string): boolean;
}
72 changes: 72 additions & 0 deletions src/recommendation/handlerImpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

import * as vscode from 'vscode';
import { IHandler } from './handler';

const KEY_RECOMMENDATION_USER_CHOICE_MAP = 'recommendationUserChoice';

async function installExtensionCmdHandler(extensionName: string, displayName: string): Promise<unknown> {
return vscode.window
.withProgress(
{ location: vscode.ProgressLocation.Notification, title: `Installing ${displayName || extensionName}...` },
() => {
return vscode.commands.executeCommand('workbench.extensions.installExtension', extensionName);
}
)
.then(() => {
vscode.window.showInformationMessage(`Successfully installed ${displayName || extensionName}.`);
});
}

enum UserChoice {
install = 'Install',
never = 'Never',
later = 'Later',
}

export class HandlerImpl implements IHandler {
userChoice: () => unknown;
storeUserChoice: (choice: unknown) => void;
constructor(context: vscode.ExtensionContext) {
this.userChoice = () => {
return context.globalState.get(KEY_RECOMMENDATION_USER_CHOICE_MAP, {});
};

this.storeUserChoice = (choice: unknown) => {
context.globalState.update(KEY_RECOMMENDATION_USER_CHOICE_MAP, choice);
};
}

isExtensionInstalled(extName: string): boolean {
return !!vscode.extensions.getExtension(extName);
}

canRecommendExtension(extName: string): boolean {
return this.userChoice()[extName] !== UserChoice.never && !this.isExtensionInstalled(extName);
}

async handle(extName: string, message: string): Promise<void> {
if (this.isExtensionInstalled(extName)) {
return;
}

const choice = this.userChoice();
if (choice[extName] === UserChoice.never) {
return;
}

const actions: Array<string> = Object.values(UserChoice);
const answer = await vscode.window.showInformationMessage(message, ...actions);
if (answer === UserChoice.install) {
await installExtensionCmdHandler(extName, extName);
}

choice[extName] = answer;
this.storeUserChoice(choice);
}
}
15 changes: 15 additions & 0 deletions src/recommendation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

import * as vscode from 'vscode';
import { HandlerImpl } from './handlerImpl';
import { initializeRecommendation as initOpenShiftToolkit } from './openShiftToolkit';

export function initializeRecommendation(context: vscode.ExtensionContext): void {
const handler = new HandlerImpl(context);
initOpenShiftToolkit(context, handler);
}
46 changes: 46 additions & 0 deletions src/recommendation/openShiftToolkit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';

import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { IHandler } from './handler';

const EXTENSION_NAME = 'redhat.vscode-openshift-connector';
const GH_ORG_URL = `https://github.com/redhat-developer/vscode-openshift-tools`;
const RECOMMENDATION_MESSAGE = `The workspace has a devfile.yaml. Install [OpenShift Toolkit](${GH_ORG_URL}) extension for assistance with deploying to a cluster?`;
const YAML_RECOMMENDATIONS_SHOW = 'yaml.recommendations.show';

function isDevfileYAML(uri: vscode.Uri): boolean {
if (fs.lstatSync(uri.fsPath).isDirectory()) {
const devFileYamlPath = path.join(uri.fsPath, 'devfile.yaml');
return fs.existsSync(devFileYamlPath);
}
return !!uri.path && path.basename(uri.path).toLowerCase() === 'devfile.yaml';
}

export function initializeRecommendation(context: vscode.ExtensionContext, handler: IHandler): void {
const show = vscode.workspace.getConfiguration().get(YAML_RECOMMENDATIONS_SHOW);
if (!show) {
return;
}
if (!handler.canRecommendExtension(EXTENSION_NAME)) {
return;
}
context.subscriptions.push(
vscode.workspace.onDidOpenTextDocument((e) => {
if (isDevfileYAML(e.uri)) {
handler.handle(EXTENSION_NAME, RECOMMENDATION_MESSAGE);
}
})
);

const isdevfileYAMLOpened = vscode.workspace.workspaceFolders.findIndex((workspace) => isDevfileYAML(workspace.uri)) !== -1;
if (isdevfileYAMLOpened) {
handler.handle(EXTENSION_NAME, RECOMMENDATION_MESSAGE);
}
}
2 changes: 2 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const clientWeb = {
fallback: {
path: require.resolve('path-browserify'),
util: require.resolve('util'),
fs: false,
},
},
module: {
Expand Down Expand Up @@ -138,6 +139,7 @@ const serverWeb = {
path: require.resolve('path-browserify/'),
url: require.resolve('url/'),
buffer: require.resolve('buffer/'),
fs: false,
},
},
plugins: [
Expand Down