Skip to content

Commit 358bfee

Browse files
committed
CodeLens to apply and delete a k8s YAML file
Closes #2873 Signed-off-by: David Thompson <davthomp@redhat.com>
1 parent 3d3aebb commit 358bfee

File tree

6 files changed

+134
-0
lines changed

6 files changed

+134
-0
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
"onCommand:openshift.oc.about",
191191
"onCommand:openshift.output",
192192
"onCommand:openshift.create",
193+
"onCommand:openshift.delete",
193194
"onCommand:openshift.open.developerConsole",
194195
"onCommand:openshift.open.developerConsole.palette",
195196
"onCommand:openshift.explorer.addCluster",
@@ -263,6 +264,11 @@
263264
"title": "Create",
264265
"category": "OpenShift"
265266
},
267+
{
268+
"command": "openshift.delete",
269+
"title": "Delete",
270+
"category": "OpenShift"
271+
},
266272
{
267273
"command": "clusters.openshift.build.start",
268274
"title": "Start Build",

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { setupWorkspaceDevfileContext } from './util/workspace';
3131
import { registerCommands } from './vscommand';
3232
import { OpenShiftTerminalManager } from './webview/openshift-terminal/openShiftTerminal';
3333
import { WelcomePage } from './welcomePage';
34+
import { registerYamlHandlers } from './yaml/yamlDocumentFeatures';
3435

3536
import fsx = require('fs-extra');
3637

@@ -104,6 +105,7 @@ export async function activate(extensionContext: ExtensionContext): Promise<unkn
104105
ComponentsTreeDataProvider.instance.createTreeView('openshiftComponentsView'),
105106
setupWorkspaceDevfileContext(),
106107
window.registerWebviewViewProvider('openShiftTerminalView', OpenShiftTerminalManager.getInstance(), { webviewOptions: { retainContextWhenHidden: true, } }),
108+
...registerYamlHandlers(),
107109
];
108110
disposable.forEach((value) => extensionContext.subscriptions.push(value));
109111

src/oc/ocWrapper.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ export class Oc {
124124
);
125125
}
126126

127+
/**
128+
* Delete the Kubernetes object described by the given file.
129+
*
130+
* @param file the file containing the spec of the kubernetes object to delete
131+
*/
132+
public async deleteKubernetesObjectFromFile(file: string): Promise<void> {
133+
await CliChannel.getInstance().executeTool(
134+
new CommandText('oc', 'delete', [new CommandOption('-f', file)])
135+
);
136+
}
137+
127138
/**
128139
* Returns the username of the current user.
129140
*

src/yaml/yamlDocumentFeatures.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
6+
import { KubernetesObject } from '@kubernetes/client-node';
7+
import { load as loadYaml } from 'js-yaml';
8+
import * as vscode from 'vscode';
9+
10+
const YAML_SELECTOR: vscode.DocumentSelector = {
11+
language: 'yaml',
12+
scheme: 'file'
13+
};
14+
15+
const RANGE: vscode.Range = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1));
16+
17+
export function registerYamlHandlers(): vscode.Disposable[] {
18+
const disposables: vscode.Disposable[] = [];
19+
disposables.push(
20+
vscode.languages.registerCodeLensProvider(YAML_SELECTOR, new YamlCodeLensProvider()));
21+
return disposables;
22+
}
23+
24+
class YamlCodeLensProvider implements vscode.CodeLensProvider {
25+
provideCodeLenses(document: vscode.TextDocument, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.CodeLens[]> {
26+
27+
try {
28+
29+
const objectTexts: string[] = document.getText().split(/(?:^---\r?\n)|(?:\n---\r?\n)/).filter(text => text && text.length > 0);
30+
31+
for (const objectText of objectTexts) {
32+
const yaml = loadYaml(objectText) as KubernetesObject;
33+
34+
// heuristic to check if it's a k8s yaml
35+
if (!yaml.apiVersion || !yaml.kind || !yaml.metadata) {
36+
return [];
37+
}
38+
}
39+
40+
} catch (e) {
41+
return [];
42+
}
43+
44+
return [
45+
{
46+
isResolved: true,
47+
range: RANGE,
48+
command: {
49+
command: 'openshift.create',
50+
title: 'Apply YAML to cluster',
51+
tooltip: 'Performs `kubectl apply -f` on this file'
52+
}
53+
},
54+
{
55+
isResolved: true,
56+
range: RANGE,
57+
command: {
58+
command: 'openshift.delete',
59+
title: 'Delete YAML from cluster',
60+
tooltip: 'Performs `kubectl delete -f` on this file'
61+
}
62+
}
63+
];
64+
}
65+
}

src/yamlFileCommands.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,47 @@ export class YamlFileCommands {
5454
await OcWrapper.Instance.createKubernetesObjectFromFile(document.fileName);
5555
return 'Resources were successfully created.';
5656
}
57+
58+
@vsCommand('openshift.delete')
59+
@clusterRequired()
60+
public static async delete(): Promise<string | null> {
61+
const document = window.activeTextEditor ? window.activeTextEditor.document : undefined;
62+
const pleaseSave = 'Please save your changes before executing \'OpenShift: Delete\' command.';
63+
let message: string;
64+
65+
if (!document
66+
|| !(document.fileName.endsWith('.yaml') || document.fileName.endsWith('.json'))) {
67+
message =
68+
'\'OpenShift: Delete\' command requires a .yaml or a .json file opened in editor.';
69+
}
70+
71+
if (!message && document.isUntitled) {
72+
message = pleaseSave;
73+
}
74+
75+
if (!message && document.isDirty) {
76+
const save = 'Save';
77+
const action = await window.showInformationMessage('Editor has unsaved changes.', save);
78+
if (action !== save) {
79+
message = pleaseSave;
80+
} else {
81+
await document.save();
82+
}
83+
}
84+
85+
const activeProject = await YamlFileCommands.odo.getActiveProject();
86+
87+
if (!message && !activeProject) {
88+
message = '\'OpenShift: Delete\' requires setting a project as active, and none is currently set.';
89+
}
90+
91+
if (message) {
92+
void window.showWarningMessage(message);
93+
return null;
94+
}
95+
96+
await OcWrapper.Instance.deleteKubernetesObjectFromFile(document.fileName);
97+
return 'Resources were successfully deleted.';
98+
}
99+
57100
}

test/integration/ocWrapper.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ suite('./oc/ocWrapper.ts', function () {
152152
const deployments = await Oc.Instance.getKubernetesObjects('Deployment');
153153
expect(deployments).to.have.length(0);
154154
});
155+
156+
test('deleteKubernetesObjectFromFile()', async function() {
157+
await Oc.Instance.createKubernetesObjectFromFile(yamlFile);
158+
await Oc.Instance.deleteKubernetesObjectFromFile(yamlFile);
159+
const deployments = await Oc.Instance.getKubernetesObjects('Deployment');
160+
expect(deployments).to.have.length(0);
161+
});
155162
});
156163

157164
test('getConsoleInfo()', async function() {

0 commit comments

Comments
 (0)