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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ src/webview/welcome
src/webview/helm-chart
src/webview/feedback
src/webview/serverless-function
src/webview/serverless-manage-repository
# vendored from https://github.com/IonicaBizau/git-url-parse, see https://github.com/IonicaBizau/git-url-parse/pull/159
src/util/gitParse.ts
test/sandbox-registration
1 change: 1 addition & 0 deletions build/esbuild.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const webviews = [
'welcome',
'feedback',
'serverless-function',
'serverless-manage-repository',
'add-service-binding',
];

Expand Down
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,12 @@
"category": "OpenShift",
"icon": "$(plus)"
},
{
"command": "openshift.Serverless.manageRepository",
"title": "Manage Knative Function Template Repositories",
"category": "OpenShift",
"icon": "$(gist)"
},
{
"command": "openshift.Serverless.refresh",
"title": "Refresh Serverless Function View",
Expand Down Expand Up @@ -1299,6 +1305,11 @@
"when": "view == openshiftServerlessFunctionsView",
"group": "navigation@1"
},
{
"command": "openshift.Serverless.manageRepository",
"when": "view == openshiftServerlessFunctionsView",
"group": "navigation@2"
},
{
"command": "openshift.component.openCreateComponent",
"when": "view == openshiftComponentsView",
Expand Down
40 changes: 31 additions & 9 deletions src/serverlessFunction/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,41 @@ export class ServerlessCommand {
}

static config(functionPath: string, mode: string, isAdd: boolean): CommandText {
const option = isAdd ? mode === 'git' ? 'set' : 'add' : 'remove';
const commandText = new CommandText('func', 'config', [
new CommandOption(mode),
new CommandOption(option),
new CommandOption('-p', functionPath)
]);
if (isAdd) {
if (mode === 'git') {
commandText.addOption(new CommandOption('set'));
} else {
commandText.addOption(new CommandOption('add'));
}
} else {
commandText.addOption(new CommandOption('remove'));
}
return commandText;
}

static addRepo(name: string, gitURL: string): CommandText {
const commandText = new CommandText('func', 'repository');
commandText.addOption(new CommandOption('add'));
commandText.addOption(new CommandOption(name));
commandText.addOption(new CommandOption(gitURL));
return commandText;
}

static deleteRepo(name: string): CommandText {
const commandText = new CommandText('func', 'repository');
commandText.addOption(new CommandOption('remove'));
commandText.addOption(new CommandOption(name));
return commandText;
}

static list(): CommandText {
const commandText = new CommandText('func', 'repository');
commandText.addOption(new CommandOption('list'));
return commandText;
}

static renameRepo(oldName: string, newName: string): CommandText {
const commandText = new CommandText('func', 'repository');
commandText.addOption(new CommandOption('rename'));
commandText.addOption(new CommandOption(oldName));
commandText.addOption(new CommandOption(newName));
return commandText;
}
}
96 changes: 96 additions & 0 deletions src/serverlessFunction/manageRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { OdoImpl } from '../odo';
import sendTelemetry from '../telemetry';
import { ServerlessCommand } from './commands';

export class ManageRepository {

private static instance: ManageRepository;

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

public async deleteRepo(name: string): Promise<boolean> {
await sendTelemetry('openshift.managerepo.delete', {
name
});
const result = await OdoImpl.Instance.execute(ServerlessCommand.deleteRepo(name), '', false);
if (result.error) {
await sendTelemetry('openshift.managerepo.delete.error', {
error: result.error.message
});
void vscode.window.showErrorMessage(result.error.message);
return false;
}
return true;
}

public async renameRepo(oldName: string, newName: string): Promise<boolean> {
await sendTelemetry('openshift.managerepo.rename', {
oldName,
newName
});
const result = await OdoImpl.Instance.execute(ServerlessCommand.renameRepo(oldName, newName), '', false);
if (result.error) {
await sendTelemetry('openshift.managerepo.rename.error', {
error: result.error.message
});
void vscode.window.showErrorMessage(result.error.message);
return false;
}
await sendTelemetry('openshift.managerepo.rename.success', {
message: `Repo ${newName} renamed successfully`
});
return true;
}

public async addRepo(name: string, url: string): Promise<boolean> {
await sendTelemetry('openshift.managerepo.add', {
name, url
});
const result = await OdoImpl.Instance.execute(ServerlessCommand.addRepo(name, url), '', false);
if (result.error) {
await sendTelemetry('openshift.managerepo.add.error', {
error: result.error.message
});
void vscode.window.showErrorMessage(result.error.message);
return false;
} else if (result.stdout.length === 0 && result.stderr.length === 0) {
await sendTelemetry('openshift.managerepo.add.success', {
name,
message: 'Repo added successfully'
});
void vscode.window.showInformationMessage(`Repository ${name} added successfully`);
return true;
}
await sendTelemetry('openshift.managerepo.add.error', {
error: result.stderr
});
return false;
}

public async list(): Promise<string[]> {
await sendTelemetry('openshift.managerepo.list');
const result = await OdoImpl.Instance.execute(ServerlessCommand.list(), '', false);
if (result.error) {
await sendTelemetry('openshift.managerepo.list.error', {
error: result.error.message
});
void vscode.window.showErrorMessage(result.error.message);
return [];
}
await sendTelemetry('openshift.managerepo.list.success', {
repos: result.stdout.split('\n')
});
return result.stdout.split('\n');
}
}
6 changes: 6 additions & 0 deletions src/serverlessFunction/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { FunctionContextType, FunctionObject, FunctionStatus } from './types';
import ServerlessFunctionViewLoader from '../webview/serverless-function/serverlessFunctionLoader';
import { Functions } from './functions';
import { vsCommand } from '../vscommand';
import ManageRepositoryViewLoader from '../webview/serverless-manage-repository/manageRepositoryLoader';

const kubeConfigFolder: string = path.join(Platform.getUserHomePath(), '.kube');

Expand Down Expand Up @@ -203,6 +204,11 @@ export class ServerlessFunctionView implements TreeDataProvider<ExplorerItem>, D
await ServerlessFunctionViewLoader.loadView('Serverless Function - Create');
}

@vsCommand('openshift.Serverless.manageRepository')
static async openManageRepository(): Promise<void> {
await ManageRepositoryViewLoader.loadView('Manage Repository');
}

@vsCommand('openshift.Serverless.refresh')
static refresh(target?: ExplorerItem) {
ServerlessFunctionView.getInstance().refresh(target);
Expand Down
69 changes: 68 additions & 1 deletion src/webview/common-ext/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import { Uri, WebviewPanel, extensions } from 'vscode';
import OpenShiftItem from '../../openshift/openshiftItem';
import { ExtensionID } from '../../util/constants';
import { gitUrlParse } from '../../util/gitParse';
import { validateGitURLProps } from '../common/propertyTypes';

export type Message = {
action: string;
data: any;
};

export async function loadWebviewHtml(webviewName: string, webviewPanel: WebviewPanel, additionalInjections?: Map<string, string>): Promise<string> {

Expand All @@ -28,7 +36,7 @@ export async function loadWebviewHtml(webviewName: string, webviewPanel: Webview
style-src 'self' vscode-resource: 'unsafe-inline';">`;
const htmlWithDefaultInjections = `${htmlString}`
.replace('%PLATFORM%', process.platform)
.replace('%SCRIPT%',`${reactJavascriptUri}`)
.replace('%SCRIPT%', `${reactJavascriptUri}`)
.replace('%BASE_URL%', `${reactJavascriptUri}`)
.replace('%STYLE%', `${reactStylesheetUri}`)
.replace('<!-- meta http-equiv="Content-Security-Policy" -->', meta);
Expand All @@ -41,3 +49,62 @@ export async function loadWebviewHtml(webviewName: string, webviewPanel: Webview
}
return htmlWithAdditionalInjections;
}

function isGitURL(host: string): boolean {
return [
'github.com',
'bitbucket.org',
'gitlab.com',
'git.sr.ht',
'codeberg.org',
'gitea.com',
].includes(host);
}

export function validateGitURL(event: Message): validateGitURLProps {
if (typeof event.data === 'string' && (event.data).trim().length === 0) {
return {
url: event.data,
error: true,
helpText: 'Please enter a Git URL.'
} as validateGitURLProps
}
try {
const parse = gitUrlParse(event.data);
const isGitRepo = isGitURL(parse.host);
if (!isGitRepo) {
throw 'Invalid Git URL';
}
if (parse.organization !== '' && parse.name !== '') {
return {
url: event.data,
error: false,
helpText: 'The git repo URL is valid.'
} as validateGitURLProps
}
return {
url: event.data,
error: true,
helpText: 'URL is missing organization or repo name.'
} as validateGitURLProps

} catch (e) {
return {
url: event.data,
error: true,
helpText: 'Invalid Git URL.'
} as validateGitURLProps
}
}

export function validateName(value: string): string | null {
let validationMessage = OpenShiftItem.emptyName('Required', value.trim());
if (!validationMessage) {
validationMessage = OpenShiftItem.validateMatches(
'Only lower case alphabets and numeric characters or \'-\', start and ends with only alphabets',
value,
);
}
if (!validationMessage) { validationMessage = OpenShiftItem.lengthName('Should be between 2-63 characters', value, 0); }
return validationMessage;
}
8 changes: 6 additions & 2 deletions src/webview/common/propertyTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { ChangeEvent } from 'react';
import { ComponentTypeDescription, Registry } from '../../odo/componentType';
import { StarterProject } from '../../odo/componentTypeDescription';
import { ChartResponse } from '../helm-chart/helmChartType';
Expand Down Expand Up @@ -84,3 +82,9 @@ export interface RunFunctionPageProps extends DefaultProps {
skip: (stepCount: number) => void;
onRunSubmit: (folderPath: Uri, build: boolean) => void;
}

export interface validateGitURLProps {
url: string;
error: boolean;
helpText: string;
}
18 changes: 0 additions & 18 deletions src/webview/common/utils.ts

This file was deleted.

Loading