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

webview to start pipeline #323

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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 @@ -6,3 +6,4 @@ out
coverage

preview
*.jsx
3,621 changes: 3,049 additions & 572 deletions package-lock.json

Large diffs are not rendered by default.

39 changes: 36 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@
"type": "boolean",
"default": false,
"description": "Enable/disable to Deploy the yaml resources on cluster"
},
"vs-tekton.StartPipeline": {
"Title": "Start Pipeline",
"type": "boolean",
"default": false,
"description": "Enable/disable to Start Pipeline in webView"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Enable/disable to Start Pipeline in webView Is not clear as for me,
maybe Enable WebView Wizard to Start Pipeline is better.
As for me Enable/disable is very confusing.

}
}
},
Expand Down Expand Up @@ -877,7 +883,9 @@
"scripts": {
"verify": "node ./out/build/verify-tools.js",
"vscode:prepublish": "npm run build",
"compile": "tsc -p ./ && npm run build-preview",
"compile": "tsc -p ./ && npm run build-preview && npm run webview-start",
"webview-start": "webpack-cli --mode development --config src/view/webpack.config.js",
"webview-start-watch": "webpack-cli -w --mode development --config src/view/webpack.config.js",
"watch": "tsc -watch -p ./",
"clean": "rimraf out && rimraf preview",
"test": "npm run clean && npm run compile && npm run verify && node ./out/build/install-vscode.js && node ./out/build/unit-tests.js",
Expand All @@ -892,13 +900,15 @@
"icons-build": "node ./out/build/build-svg-icons.js"
},
"devDependencies": {
"@patternfly/react-core": "^3.158.1",
"@types/byline": "^4.2.31",
"@types/chai": "^4.1.7",
"@types/collections": "^5.0.0",
"@types/cytoscape": "^3.14.0",
"@types/debounce": "^1.2.0",
"@types/fs-extra": "^8.0.0",
"@types/humanize-duration": "^3.18.0",
"@types/immutable": "3.x",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^5.2.7",
"@types/node": "^12.0.10",
Expand All @@ -916,49 +926,71 @@
"@typescript-eslint/parser": "^2.12.0",
"chai": "^4.2.0",
"codecov": "^3.5.0",
"css-loader": "^3.5.3",
"cytoscape": "^3.14.0",
"cytoscape-dagre": "^2.2.2",
"decache": "^4.5.1",
"eslint": "^6.7.2",
"eslint-plugin-header": "^3.0.0",
"file-loader": "^6.0.0",
"glob": "^7.1.3",
"istanbul": "^0.4.5",
"mocha": "^6.2.2",
"mocha-jenkins-reporter": "^0.4.3",
"node-sass": "^4.14.1",
"npm-run-all": "^4.1.5",
"proxyquire": "^2.1.0",
"remap-istanbul": "^0.13.0",
"rimraf": "^3.0.2",
"sass-loader": "^8.0.2",
"simple-svg-tools": "^1.1.12",
"sinon": "^7.3.2",
"sinon-chai": "^3.3.0",
"source-map-support": "^0.5.16",
"style-loader": "^1.2.1",
"thread-loader": "^2.1.3",
"tmp": "0.1.0",
"ts-loader": "^6.2.1",
"typescript": "^3.5.2",
"vscode-test": "^1.3.0",
"walker": "^1.0.7",
"webpack": "^4.41.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
},
"dependencies": {
"@kubernetes/client-node": "^0.10.2",
"@patternfly/patternfly": "2.71.5",
Copy link
Collaborator

Choose a reason for hiding this comment

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

All dependencies that we use in any webview should be moved to devDependencies as we compiled them it webpack bundle, and we do not need to distribute them inside vsix package

"@patternfly/react-catalog-view-extension": "1.4.58",
"binary-search": "^1.3.5",
"bootstrap-sass": "^3.4.1",
"byline": "^5.0.0",
"classnames": "^2.2.6",
"clsx": "^1.1.0",
"dart-sass": "^1.25.0",
"debounce": "^1.2.0",
"event-stream": "3.3.4",
"formik": "^2.1.4",
"fs-extra": "^7.0.1",
"fuzzysearch": "^1.0.3",
"git-fetch-pack": "^0.1.1",
"git-transport-protocol": "^0.1.0",
"immutable": "3.x",
"hasha": "5.0.0",
"html-webpack-plugin": "^4.3.0",
"humanize-duration": "^3.21.0",
"js-yaml": "^3.13.1",
"jstream": "^1.1.1",
"lodash": "^4.17.15",
"lodash-es": "^4.17.15",
"mkdirp": "^0.5.1",
"node-yaml-parser": "0.0.9",
"open": "^6.4.0",
"pluralize": "^4.0.0",
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",
"react-dom": "^16.13.1",
"request": "^2.88.0",
"request-progress": "^3.0.0",
"semver": "^6.3.0",
Expand All @@ -967,6 +999,7 @@
"targz": "^1.0.1",
"unzip-stream": "^0.3.0",
"validator": "^11.0.0",
"vscode-kubernetes-tools-api": "1.1.0"
"vscode-kubernetes-tools-api": "1.1.0",
"yup": "^0.29.1"
}
}
17 changes: 15 additions & 2 deletions src/tekton/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@
import { TektonItem } from './tektonitem';
import { TektonNode, Command } from '../tkn';
import { Progress } from '../util/progress';
import { window } from 'vscode';
import { window, workspace } from 'vscode';
import * as cliInstance from '../cli';
import { cli } from '../cli';
import { TknPipelineTrigger } from '../tekton';
import { Trigger, PipelineContent } from './pipelinecontent';
import pipelineViewLoader from '../view/pipeline/pipelineViewLoader';
import { pipelineData } from './webviewstartpipeline';

export class Pipeline extends TektonItem {


static checkWebViewStartPipeline(): boolean {
return workspace
.getConfiguration('vs-tekton')
.get<boolean>('StartPipeline');
}

static async start(pipeline: TektonNode): Promise<string> {
if (Pipeline.checkWebViewStartPipeline()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe having separate command for webview wizard will be better? @siamaksade ?

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 think enabling webview from setting would be better.

pipelineViewLoader.loadView('Start Pipeline', await pipelineData(pipeline.getName()));
return null;
}
if (!pipeline) {
pipeline = await window.showQuickPick(await Pipeline.getPipelineNames(), {placeHolder: 'Select Pipeline to start', ignoreFocusOut: true});
}
Expand All @@ -33,7 +46,7 @@ export class Pipeline extends TektonItem {
const pipelineTrigger = data.map<Trigger>(value => ({
name: value.metadata.name,
resources: value.spec.resources,
params: value.spec.params ? value.spec.params : undefined,
parameters: value.spec.params ? value.spec.params : undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

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

there you can use value.spec.params ?? undefined see nullish-coalescing But in this case is no sense to do that check.

workspaces: value.spec['workspaces'] ? value.spec['workspaces'] : undefined,
serviceAcct: value.spec.serviceAccount ? value.spec.serviceAccount : undefined
})).filter(function (obj) {
Expand Down
23 changes: 13 additions & 10 deletions src/tekton/pipelinecontent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ export interface Workspaces {
value?: string;
subPath?: string;
emptyDir?: string;
type?: string;
data?: any;
}

export interface Resources {
selection?: string;
name: string;
resourceRef: string;
resourceType?: string;
Expand All @@ -44,15 +47,15 @@ export interface Params {
export interface StartObject {
name: string;
resources: Resources[];
params: Params[] | undefined;
parameters: Params[] | undefined;
workspaces: Workspaces[];
serviceAccount: string | undefined;
}

export interface Trigger {
name: string;
resources: NameType[];
params?: Params[];
parameters?: Params[];
workspaces?: Workspaces[];
serviceAcct: string | undefined;
}
Expand Down Expand Up @@ -87,10 +90,10 @@ export class PipelineContent extends TektonItem {
return pick.label;
}

static async inputParameters(context: Trigger[], params: QuickPickItem[], message: string): Promise<Params[]> {
static async inputParameters(context: Trigger[], parameters: QuickPickItem[], message: string): Promise<Params[]> {
const paramData = [];
for (const item of params) {
const selectedParam = context[0].params.find(x => x.name === item.label);
for (const item of parameters) {
const selectedParam = context[0].parameters.find(x => x.name === item.label);
const title = `Params: ${item['label']}`;
const paramVal = await PipelineContent.getParamValues(selectedParam.name);
const pick = await multiStepInput.showQuickPick({
Expand Down Expand Up @@ -235,12 +238,12 @@ export class PipelineContent extends TektonItem {

static async startObject(context: Trigger[], message: string): Promise<StartObject> {
const resources: QuickPickItem[] | undefined = context[0].resources ? context[0].resources.map<QuickPickItem>(label => ({ label: label.name, resourceGitImageType: label['type'] ? label['type'] : undefined ,resourceType: label['resourceType'] ? label['resourceType'] : undefined })) : undefined;
const params: QuickPickItem[] | undefined = context[0].params ? context[0].params.map<QuickPickItem>(label => ({ label: label.name })) : undefined;
const parameters: QuickPickItem[] | undefined = context[0].parameters ? context[0].parameters.map<QuickPickItem>(label => ({ label: label.name })) : undefined;
const workspaces: QuickPickItem[] | undefined = context[0].workspaces ? context[0].workspaces.map<QuickPickItem>(label => ({ label: label.name })) : undefined;

const inputStart = {
resources: [],
params: [],
parameters: [],
workspaces: []
} as StartObject;
inputStart.name = context[0].name;
Expand All @@ -257,9 +260,9 @@ export class PipelineContent extends TektonItem {
inputStart.resources.push(selectedResource);
}
}
if (params) {
const paramData = await PipelineContent.inputParameters(context, params, message);
paramData.map((value: Params) => { inputStart.params.push(value); })
if (parameters) {
const paramData = await PipelineContent.inputParameters(context, parameters, message);
paramData.map((value: Params) => { inputStart.parameters.push(value); })
}
if (inputStart.serviceAccount) {
await PipelineContent.pickServiceAcct(inputStart);
Expand Down
23 changes: 20 additions & 3 deletions src/tekton/tektonitem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { Tkn, tkn as tknImpl, TektonNode, ContextType } from '../tkn';
import { Tkn, tkn as tknImpl, TektonNode, ContextType, Command } from '../tkn';
import { PipelineExplorer, pipelineExplorer } from '../pipeline/pipelineExplorer';
import { workspace, window } from 'vscode';
import { tektonFSUri } from '../util/tekton-vfs';
import { TknPipelineResource } from '../tekton';
import { Ref } from './pipelinecontent';

const errorMessage = {
Pipeline: 'You need at least one Pipeline available. Please create new Tekton Pipeline and try again.',
Expand All @@ -22,8 +24,8 @@ const errorMessage = {
};

export abstract class TektonItem {
protected static readonly tkn: Tkn = tknImpl;
protected static readonly explorer: PipelineExplorer = pipelineExplorer;
static readonly tkn: Tkn = tknImpl;
static readonly explorer: PipelineExplorer = pipelineExplorer;

static validateUniqueName(data: Array<TektonNode>, value: string): string {
const tektonNode = data.find((tektonNode) => tektonNode.getName() === value);
Expand Down Expand Up @@ -53,6 +55,21 @@ export abstract class TektonItem {
return pipelineRunList;
}

static async pipelineResourceReturn(): Promise<Ref[]> {
let pipeR: TknPipelineResource[] = [];
const result = await TektonItem.tkn.execute(Command.listPipelineResources(), process.cwd(), false);
try {
pipeR = JSON.parse(result.stdout).items;
} catch (ignore) {
//show no pipelines if output is not correct json
}
const pipeResources = pipeR.map<Ref>(value => ({
name: value.metadata.name,
type: value.spec.type,
}));
return pipeResources;
}

static async getTaskNames(): Promise<TektonNode[]> {
const taskList: Array<TektonNode> = await TektonItem.tkn.getTasks();
if (taskList.length === 0) throw Error(errorMessage.Task);
Expand Down
101 changes: 101 additions & 0 deletions src/tekton/webviewstartpipeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { Command } from '../tkn';
import { TektonItem } from './tektonitem';

export interface Param {
name: string;
type?: string;
}

export interface PipelineParam extends Param {
default?: string | string[];
description?: string;
}

export interface PipelineResource {
name: string;
type: string;
}

export interface PipelineWorkspace extends Param {
type?: string;
workspace?: string;
data?: {
[key: string]: string;
};
}


export interface PipelineTaskRef {
kind?: string;
name: string;
}

export interface PipelineTaskParam {
name: string;
value: any;
}

export interface PipelineTaskResource {
name: string;
resource?: string;
from?: string[];
}

export interface PipelineTaskResources {
inputs?: PipelineTaskResource[];
outputs?: PipelineTaskResource[];
}

export interface PipelineTask {
name: string;
runAfter?: string[];
taskRef: PipelineTaskRef;
params?: PipelineTaskParam[];
resources?: PipelineTaskResources;
workspaces?: PipelineWorkspace[];
}

interface TknResource {
pipeline: {
spec: {
params?: PipelineParam[];
resources?: PipelineResource[];
workspaces?: PipelineWorkspace[];
tasks: PipelineTask[];
serviceAccountName?: string;
};
};
pipelineResource: any;
Secret: any;
ConfigMap: any;
PersistentVolumeClaim: any;
}


export const pipelineData = async (name: string) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you can define function instead of exporting constant, which you assign lambda, or you have particular reason to do that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No particular reason for using lambda. I will use function here.

const pipelineData: TknResource = {
pipeline: undefined,
pipelineResource: undefined,
Secret: undefined,
ConfigMap: undefined,
PersistentVolumeClaim: undefined
};
const pipeline = await TektonItem.tkn.execute(Command.getPipeline(name), process.cwd(), false);
pipelineData.pipeline = JSON.parse(pipeline.stdout);
if (pipelineData.pipeline.spec.workspaces) {
const secret = await TektonItem.tkn.execute(Command.workspace('Secret'), process.cwd(), false);
pipelineData.Secret = JSON.parse(secret.stdout).items;
const configMap = await TektonItem.tkn.execute(Command.workspace('ConfigMap'), process.cwd(), false);
pipelineData.ConfigMap = JSON.parse(configMap.stdout).items;
const pvc = await TektonItem.tkn.execute(Command.workspace('PersistentVolumeClaim'), process.cwd(), false);
pipelineData.PersistentVolumeClaim = JSON.parse(pvc.stdout).items;
}
const resource = await TektonItem.tkn.execute(Command.getPipelineResource(), process.cwd(), false);
pipelineData.pipelineResource = JSON.parse(resource.stdout).items;
return pipelineData;
}
Loading