forked from redhat-developer/vscode-openshift-tools
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Devfile Registry editor is to allow devfile version selection and use…
… when creating a component redhat-developer#4189 Fixes: redhat-developer#4189 Issue: redhat-developer#3850 Signed-off-by: Victor Rubezhny <[email protected]>
- Loading branch information
Showing
30 changed files
with
1,620 additions
and
960 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/*----------------------------------------------------------------------------------------------- | ||
* Copyright (c) Red Hat, Inc. All rights reserved. | ||
* Licensed under the MIT License. See LICENSE file in the project root for license information. | ||
*-----------------------------------------------------------------------------------------------*/ | ||
// | ||
// The Types representing the output of | ||
// 'odo registry [--devfile-registry="<Devfile Registry Name>" -o=json' | ||
// | ||
|
||
import { Data } from '../odo/componentTypeDescription'; | ||
|
||
export type DevfileRegistryInfo = { | ||
name: string, | ||
url: string, | ||
secure: boolean | ||
}; | ||
|
||
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/*----------------------------------------------------------------------------------------------- | ||
* 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 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 | ||
*/ | ||
public 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 registries with their devfiles attached. | ||
* | ||
* @returns a list of the devfile registries with their devfiles attached | ||
*/ | ||
public async getRegistryDevfileInfos(registryUrl?: string): Promise<DevfileInfo[]> { | ||
// Return only registries registered for user (from ODO preferences) | ||
// and filter by registryUrl (if provided) | ||
const registries: Registry[] = await this.getRegistries(registryUrl); | ||
if (!registries || registries.length === 0) { | ||
throw new Error('No Devfile registries available. Default registry is missing'); | ||
} | ||
|
||
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 raw devvile text attached | ||
* | ||
* @returns a devfile data with raw devvile 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); | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Clear the Execution context as well as all cached data | ||
*/ | ||
public clearCache() { | ||
if (this.executionContext) { | ||
this.executionContext.clear(); | ||
} | ||
this.executionContext = new ExecutionContext(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.