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

Devfile Registry editor is to allow devfile version selection and use… #4467

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
4 changes: 4 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@

import { VSCodeSettings } from '@redhat-developer/vscode-redhat-telemetry/lib/common/vscode/settings';
import * as cp from 'child_process';
import * as hasha from 'hasha';
import * as vscode from 'vscode';
import { CommandText } from './base/command';
import { ToolsConfig } from './tools';
import { ChildProcessUtil, CliExitData } from './util/childProcessUtil';
import { VsCommandError } from './vscommand';

export class ExecutionContext extends Map<string, any> {
public static key(value: string): string {
return hasha(value);
}
}

export class CliChannel {
Expand Down
58 changes: 58 additions & 0 deletions src/devfile-registry/devfileInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { Registry } from '../odo/componentType';
import { Data } from '../odo/componentTypeDescription';

export type DevfileRegistryInfo = Registry;

export type DevfileLinksInfo = {
any
};

export type DevfileCommandGroupsInfo = {
build: boolean,
debug: boolean,
deploy: boolean,
run: boolean,
test: boolean
};

export type DevfileVersionInfo = {
version: string,
schemaVersion: string,
default: boolean,
description: string,
tags: string[],
icon: string,
links: DevfileLinksInfo,
commandGroups: DevfileCommandGroupsInfo,
resources: string[],
starterProjects: string[],
};

export type DevfileInfo = {
name: string,
displayName: string,
description: string,
type: string,
tags: string[],
architectures: string[],
icon: string,
projectType: string,
language: string,
provider: string,
supportUrl: string,
versions: DevfileVersionInfo[],
registry?: DevfileRegistryInfo
};

export type DevfileInfoExt = DevfileInfo & {
proposedVersion?: string
};

export type DevfileData = Data & {
yaml: string;
};
184 changes: 184 additions & 0 deletions src/devfile-registry/devfileRegistryWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*-----------------------------------------------------------------------------------------------
* 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 https from 'https';
import * as YAML from 'js-yaml';
import { ExecutionContext } from '../cli';
import { Registry } from '../odo/componentType';
import { Odo } from '../odo/odoWrapper';
import { DevfileData, DevfileInfo } from './devfileInfo';

export const DEVFILE_VERSION_LATEST: string = 'latest';

/**
* Wraps some the Devfile Registry REST API calls.
*/
export class DevfileRegistry {
private static instance: DevfileRegistry;

private executionContext: ExecutionContext = new ExecutionContext();

public static get Instance(): DevfileRegistry {
if (!DevfileRegistry.instance) {
DevfileRegistry.instance = new DevfileRegistry();
}
return DevfileRegistry.instance;
}

private constructor() {
// no state
}

/**
* Get list of Devfile Infos from the specified Registry.
*
* GET http://{registry host}/v2index/all
*
* @param url Devfile Registry URL
* @param abortTimeout (Optional) If provided, allow cancelling the operation by timeout
* @param abortController (Optional) If provided, allows cancelling the operation by signal
*/
public async getDevfileInfoList(url: string, abortTimeout?: number, abortController?: AbortController): Promise<DevfileInfo[]> {
const requestUrl = `${url}/v2index/all`;
const key = ExecutionContext.key(requestUrl);
if (this.executionContext && this.executionContext.has(key)) {
return this.executionContext.get(key);
}
const rawList = await DevfileRegistry._get(`${url}/v2index/all`, abortTimeout, abortController);
const jsonList = JSON.parse(rawList);
this.executionContext.set(key, jsonList);
return jsonList;
}

/**
* Get Devfile of specified version from Registry.
*
* GET http://{registry host}/devfiles/{stack}/{version}
*
* @param url Devfile Registry URL
* @param stack Devfile stack
* @param version (Optional) If specified, the version of Devfile to be received, otherwize 'latest' version is requested
* @param abortTimeout (Optional) If provided, allow cancelling the operation by timeout
* @param abortController (Optional) If provided, allows cancelling the operation by signal
*/
private async _getDevfile(url: string, stack: string, version?: string, abortTimeout?: number, abortController?: AbortController): Promise<string> {
const requestUrl = `${url}/devfiles/${stack}/${version ? version : DEVFILE_VERSION_LATEST}`;
const key = ExecutionContext.key(requestUrl);
if (this.executionContext && this.executionContext.has(key)) {
return this.executionContext.get(key);
}
const devfile = DevfileRegistry._get(`${url}/devfiles/${stack}/${version ? version : DEVFILE_VERSION_LATEST}`,
abortTimeout, abortController);
this.executionContext.set(key, devfile);
return devfile;
}

/**
* Returns a list of the devfile registries from ODO preferences.
*
* @returns a list of the devfile registries
*/
public async getRegistries(registryUrl?: string): Promise<Registry[]> {
// Return only registries registered for user (from ODO preferences)
// and filter by registryUrl (if provided)

let registries: Registry[] = [];
const key = ExecutionContext.key('getRegistries');
if (this.executionContext && !this.executionContext.has(key)) {
registries = await Odo.Instance.getRegistries();
this.executionContext.set(key, registries);
} else {
registries = this.executionContext.get(key);
}

return !registries ? [] :
registries.filter((reg) => {
if (registryUrl) {
return (reg.url === registryUrl)
}
return true;
});
}

/**
* Returns a list of the devfile infos for the specified registry or all the
* registries, if not specified.
*
* @returns a list of the devfile infos
*/
public async getRegistryDevfileInfos(registryUrl?: string): Promise<DevfileInfo[]> {
const registries: Registry[] = await this.getRegistries(registryUrl);
if (!registries || registries.length === 0) {
// TODO: should throw 'new Error('No Devfile registries available. Default registry is missing');'
// here so we can report this to users when a webview is open
return [];
}

const devfiles: DevfileInfo[] = [];
await Promise.all(registries
.map(async (registry): Promise<void> => {
const devfileInfoList = (await this.getDevfileInfoList(registry.url))
.filter((devfileInfo) => 'stack' === devfileInfo.type.toLowerCase());
devfileInfoList.forEach((devfileInfo) => {
devfileInfo.registry = registry;
});
devfiles.push(...devfileInfoList);
}));

return devfiles.sort((a, b) => (a.name < b.name ? -1 : 1));
}

/**
* Returns a devfile data with the raw devfile text attached
*
* @returns a devfile data with raw devfile text attached
*/
public async getRegistryDevfile(registryUrl: string, name: string, version?: string): Promise<DevfileData> {
const rawDevfile = await this._getDevfile(registryUrl, name, version ? version : 'latest');
const devfile = YAML.load(rawDevfile) as DevfileData;
devfile.yaml = rawDevfile;
return devfile;
}

private static async _get(url: string, abortTimeout?: number, abortController?: AbortController): Promise<string> {
return new Promise<string>((resolve, reject) => {
const signal = abortController?.signal;
const timeout = abortTimeout ? abortTimeout : 5000;
const options = { rejectUnauthorized: false, signal, timeout };
let result: string = '';
https.get(url, options, (response) => {
if (response.statusCode < 500) {
response.on('data', (d) => {
result = result.concat(d);
});
response.resume();
response.on('end', () => {
if (!response.complete) {
reject(new Error(`The connection was terminated while the message was still being sent: ${response.statusMessage}`));
} else {
resolve(result);
}
});
} else {
reject(new Error(`Connect error: ${response.statusMessage}`));
}
}).on('error', (e) => {
reject(new Error(`Connect error: ${e}`));
}).on('success', (s) => {
resolve(result);
});
});
}

/**
* Clears the Execution context as well as all cached data
*/
public clearCache() {
if (this.executionContext) {
this.executionContext.clear();
}
this.executionContext = new ExecutionContext();
}

}
16 changes: 8 additions & 8 deletions src/odo/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,24 @@ export class Command {

@verbose
static createLocalComponent(
type = '', // will use empty string in case of undefined type passed in
devfileType = '', // will use empty string in case of undefined devfileType passed in
devfileVersion: string = undefined,
registryName: string,
name: string,
portNumber: number,
starter: string = undefined,
useExistingDevfile = false,
customDevfilePath = '',
devfileVersion: string = undefined,
customDevfilePath = ''
): CommandText {
const cTxt = new CommandText('odo', 'init', [
new CommandOption('--name', name)
]
);
if (type !== '') {
cTxt.addOption(new CommandOption('--devfile', type));
if (devfileType !== '') {
cTxt.addOption(new CommandOption('--devfile', devfileType));
}
if (devfileVersion) {
cTxt.addOption(new CommandOption('--devfile-version', devfileVersion, false));
}
if (registryName) {
cTxt.addOption(new CommandOption('--devfile-registry', registryName));
Expand All @@ -90,9 +93,6 @@ export class Command {
if (customDevfilePath.length > 0) {
cTxt.addOption(new CommandOption('--devfile-path', customDevfilePath, false));
}
if (devfileVersion) {
cTxt.addOption(new CommandOption('--devfile-version', devfileVersion, false));
}
if (portNumber) {
cTxt.addOption(new CommandOption(' --run-port', portNumber.toString(), false));
}
Expand Down
20 changes: 0 additions & 20 deletions src/odo/components.ts

This file was deleted.

Loading
Loading