Skip to content
Open
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
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 57 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,13 @@
"onCommand:openshift.component.folder.create",
"onCommand:openshift.explorer.reportIssue",
"onCommand:clusters.openshift.openProjectConsole",
"onCommand:clusters.openshift.useProject"
"onCommand:clusters.openshift.useProject",
"onCommand:clusters.openshift.build.start",
"onCommand:clusters.openshift.build.showLog",
"onCommand:clusters.openshift.build.followLog",
"onCommand:clusters.openshift.build.delete",
"onCommand:clusters.openshift.build.delete.palette",
"onCommand:clusters.openshift.build.rebuild"
],
"main": "./out/src/extension",
"contributes": {
Expand Down Expand Up @@ -373,6 +379,31 @@
{
"command": "clusters.openshift.openProjectConsole",
"title": "Open Project in Console"
},
{
"command": "clusters.openshift.build.showLog",
"title": "Show Log",
"category": "OpenShift"
},
{
"command": "clusters.openshift.build.followLog",
"title": "Follow Log",
"category": "OpenShift"
},
{
"command": "clusters.openshift.build.delete.palette",
"title": "Delete Build",
"category": "OpenShift"
},
{
"command": "clusters.openshift.build.delete",
"title": "Delete",
"category": "OpenShift"
},
{
"command": "clusters.openshift.build.rebuild",
"title": "Rebuild",
"category": "OpenShift"
}
],
"keybindings": [
Expand Down Expand Up @@ -423,6 +454,10 @@
"command": "openshift.component.create",
"when": "view == openshiftProjectExplorer"
},
{
"command": "clusters.openshift.build.delete",
"when": "view == openshiftProjectExplorer"
},
{
"command": "openshift.app.describe",
"when": "view == openshiftProjectExplorer"
Expand Down Expand Up @@ -510,7 +545,27 @@
{
"command": "clusters.openshift.build.start",
"group": "2@0",
"when": "view == extension.vsKubernetesExplorer && viewItem =~ /vsKubernetes\\.resource(?!\\.namespace).*/i"
"when": "view == extension.vsKubernetesExplorer && viewItem == vsKubernetes.resource.bc"
},
{
"command": "clusters.openshift.build.showLog",
"group": "1@1",
"when": "view == extension.vsKubernetesExplorer && viewItem =~ /openShift\\.resource\\.build.*/i"
},
{
"command": "clusters.openshift.build.followLog",
"group": "1@2",
"when": "view == extension.vsKubernetesExplorer && viewItem =~ /openShift\\.resource\\.build.*/i"
},
{
"command": "clusters.openshift.build.delete",
"group": "2@0",
"when": "view == extension.vsKubernetesExplorer && viewItem =~ /openShift\\.resource\\.build.*/i"
},
{
"command": "clusters.openshift.build.rebuild",
"group": "1@0",
"when": "view == extension.vsKubernetesExplorer && viewItem =~ /openShift\\.resource\\.build.*/i"
},
{
"command": "openshift.catalog.listComponents",
Expand Down
17 changes: 8 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export interface CliExitData {
readonly stdout: string;
readonly stderr: string;
}
export interface ICli {
execute(cmd: string, opts?: ExecOptions): Promise<CliExitData>;
}

export interface OdoChannel {
print(text: string): void;
show(): void;
}

export class Cli implements ICli {
private static instance: Cli;
Expand Down Expand Up @@ -49,15 +57,6 @@ export class Cli implements ICli {
}
}

export interface ICli {
execute(cmd: string, opts?: ExecOptions): Promise<CliExitData>;
}

export interface OdoChannel {
print(text: string): void;
show(): void;
}

class OdoChannelImpl implements OdoChannel {
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("OpenShift");

Expand Down
14 changes: 10 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import path = require('path');
import fsx = require('fs-extra');
import * as k8s from 'vscode-kubernetes-tools-api';
import { ClusterExplorerV1 } from 'vscode-kubernetes-tools-api';
import { DeploymentConfigNodeContributor } from './k8s/deployment';
import { BuildConfigNodeContributor } from './k8s/build';
import open = require("open");
import { Build } from './k8s/build';

let clusterExplorer: k8s.ClusterExplorerV1 | undefined = undefined;
import { Odo, OdoImpl } from './odo';
import { OdoImpl } from './odo';

export let contextGlobalState: vscode.ExtensionContext;

Expand Down Expand Up @@ -54,7 +55,12 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('openshift.component.describe', (context) => execute(Component.describe, context)),
vscode.commands.registerCommand('openshift.component.describe.palette', (context) => execute(Component.describe, context)),
vscode.commands.registerCommand('openshift.component.create', (context) => execute(Component.create, context)),
vscode.commands.registerCommand('clusters.openshift.build.start', (context) => execute(Component.startBuild, context)),
vscode.commands.registerCommand('clusters.openshift.build.start', (context) => execute(Build.startBuild, context)),
vscode.commands.registerCommand('clusters.openshift.build.showLog', (context) => execute(Build.showLog, context)),
vscode.commands.registerCommand('clusters.openshift.build.followLog', (context) => execute(Build.followLog, context)),
vscode.commands.registerCommand('clusters.openshift.build.delete', (context) => execute(Build.delete, context)),
vscode.commands.registerCommand('clusters.openshift.build.delete.palette', (context) => execute(Build.delete, context)),
vscode.commands.registerCommand('clusters.openshift.build.rebuild', (context) => execute(Build.rebuild, context)),
vscode.commands.registerCommand('openshift.component.createFromLocal', (context) => execute(Component.createFromLocal, context)),
vscode.commands.registerCommand('openshift.component.createFromGit', (context) => execute(Component.createFromGit, context)),
vscode.commands.registerCommand('openshift.component.createFromBinary', (context) => execute(Component.createFromBinary, context)),
Expand Down Expand Up @@ -103,7 +109,7 @@ export async function activate(context: vscode.ExtensionContext) {
clusterExplorer.nodeSources.resourceFolder("Routes", "Routes", "Route", "route").if(isOpenShift).at("Network"),
clusterExplorer.nodeSources.resourceFolder("DeploymentConfigs", "DeploymentConfigs", "DeploymentConfig", "dc").if(isOpenShift).at("Workloads"),
clusterExplorer.nodeSources.resourceFolder("BuildConfigs", "BuildConfigs", "BuildConfig", "bc").if(isOpenShift).at("Workloads"),
new DeploymentConfigNodeContributor()
new BuildConfigNodeContributor()
];
nodeContributors.forEach(element => {
clusterExplorer.registerNodeContributor(element);
Expand Down
192 changes: 192 additions & 0 deletions src/k8s/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { QuickPickItem, window } from "vscode";
import { OdoImpl, Odo } from "../odo";
import { Progress } from "../util/progress";
import * as vscode from 'vscode';
import { ClusterExplorerV1 } from 'vscode-kubernetes-tools-api';
import * as k8s from 'vscode-kubernetes-tools-api';

export class BuildConfigNodeContributor implements ClusterExplorerV1.NodeContributor {
contributesChildren(parent: ClusterExplorerV1.ClusterExplorerNode | undefined): boolean {
return !!parent && parent.nodeType === 'resource' && parent.resourceKind.manifestKind === 'BuildConfig';
}

async getChildren(parent: ClusterExplorerV1.ClusterExplorerNode | undefined): Promise<ClusterExplorerV1.Node[]> {
const kubectl = await k8s.extension.kubectl.v1;
if (kubectl.available) {
const result = await kubectl.api.invokeCommand(`get build -o jsonpath="{range .items[?(.metadata.labels.buildconfig=='${(parent as any).name}')]}{.metadata.namespace}{','}{.metadata.name}{','}{.metadata.annotations.openshift\\.io/build\\.number}{\\"\\n\\"}{end}"`);
const builds = result.stdout.split('\n')
.filter((value) => value !== '')
.map<BuildNode>((item: string) => new BuildNode(item.split(',')[0], item.split(',')[1], Number.parseInt(item.split(',')[2])));
return builds;
}
return [];
}
}

class BuildNode implements ClusterExplorerV1.Node, ClusterExplorerV1.ClusterExplorerResourceNode {
nodeType: "resource";
readonly resourceKind: ClusterExplorerV1.ResourceKind = {
manifestKind: 'Build',
abbreviation: 'build'
};
readonly kind: ClusterExplorerV1.ResourceKind = this.resourceKind;
public id: string;
public resourceId: string;
// tslint:disable-next-line:variable-name
constructor(readonly namespace: string, readonly name: string, readonly number: number, readonly metadata?: any) {
this.id = this.resourceId = `build/${this.name}`;
}

async getChildren(): Promise<ClusterExplorerV1.Node[]> {
return [];
}

getTreeItem(): vscode.TreeItem {
const item = new vscode.TreeItem(this.name);
item.contextValue = 'openShift.resource.build';
item.command = {
arguments: [this],
command: 'extension.vsKubernetesLoad',
title: "Load"
};
return item;
}
}

export class Command {

static startBuild(buildConfig: string) {
return `oc start-build ${buildConfig}`;
}

static getBuilds(build: string) {
return `oc get build -l buildconfig=${build} -o json`;
}

static showLog(build: string, text: string) {
return `oc logs ${build}${text}`;
}

static rebuildFrom(resourceId: String) {
return `oc start-build --from-build ${resourceId}`;
}

static followLog(build: string, text: string) {
return `oc logs ${build}${text} -f`;
}

static delete(build: String) {
return `oc delete build ${build}`;
}

static getBuildConfigs() {
return `oc get buildConfig -o json`;
}
}

export class Build {
protected static readonly odo: Odo = OdoImpl.Instance;

static async getQuickPicks(cmd: string, errorMessage: string): Promise<QuickPickItem[]> {
const result = await Build.odo.execute(cmd);
const json: JSON = JSON.parse(result.stdout);
if (json['items'].length === 0) {
throw Error(errorMessage);
}
json['items'].forEach((item: any) => {
item.label = item.metadata.name;
});
return json['items'];
}

static async getBuildConfigNames(): Promise<QuickPickItem[]> {
return Build.getQuickPicks(
Command.getBuildConfigs(),
'You have no BuildConfigs available to start a build');
}

static async getBuildNames(buildConfig: string): Promise<QuickPickItem[]> {
return Build.getQuickPicks(
Command.getBuilds(buildConfig),
'You have no builds available');
}

static async selectBuild(context: any, text: string): Promise<string> {
let build: string = null;
if (context) {
build = context.impl.name;
} else {
const buildConfig = await Build.selectBuldConfig("Select a BuildConfig to see the builds");
if (buildConfig) {
const selBuild = await window.showQuickPick(this.getBuildNames(buildConfig), {placeHolder: text});
build = selBuild ? selBuild.label : null;
}
}
return build;
}

static async selectBuldConfig(placeHolderText: string): Promise<string> {
const buildConfig: any = await window.showQuickPick(this.getBuildConfigNames(), {placeHolder: placeHolderText});
return buildConfig ? buildConfig.label : null;
}

static async startBuild(context: { id: any; }): Promise<string> {
let buildName: string = context ? context.id : undefined;
let result: Promise<string> = null;
if (!buildName) buildName = await Build.selectBuldConfig("Select a BuildConfig to start a build");
if (buildName) {
result = Progress.execFunctionWithProgress(`Starting build`, () => Build.odo.execute(Command.startBuild(buildName)))
.then(() => `Build '${buildName}' successfully started`)
.catch((err) => Promise.reject(`Failed to start build with error '${err}'`));
}
return result;
}

static async showLog(context: { impl: any; }): Promise<string> {
const build = await Build.selectBuild(context, "Select a build too see the logs");
if (build) {
Build.odo.executeInTerminal(Command.showLog(build, '-build'));
}
return build;
}

static async rebuild(context: { id?: string; impl: any; }): Promise<string> {
let resourceId: string;
if (context) {
resourceId = context.impl.name;
} else {
const name = await Build.selectBuild(context, "select too rebuild");
if (name) {
resourceId = name;
}
}
if (resourceId) {
Build.odo.executeInTerminal(Command.rebuildFrom(resourceId));
}
return null;
}

static async followLog(context: { impl: any; }): Promise<string> {
const build = await Build.selectBuild(context, "Select a build too follow the logs");
if (build) {
Build.odo.executeInTerminal(Command.followLog(build, '-build'));
}
return null;
}

static async delete(context: { impl: any; }): Promise<string> {
let result: null | string | Promise<string> | PromiseLike<string> = null;
const build = await Build.selectBuild(context, "Select a build too delete");
if (build) {
result = Progress.execFunctionWithProgress(`Starting build`, () => Build.odo.execute(Command.delete(build)))
.then(() => `Build '${build}' successfully deleted`)
.catch((err) => Promise.reject(`Failed to delete build with error '${err}'`));
}
return result;
}
}
Loading