@eclipse-che/che-devworkspace-generator
Advanced tools
Comparing version 0.0.1-96cdbb4 to 0.0.1-99986b8
@@ -16,3 +16,4 @@ /********************************************************************** | ||
export declare class DevContainerComponentFinder { | ||
find(devfileContext: DevfileContext): Promise<V1alpha2DevWorkspaceSpecTemplateComponents | undefined>; | ||
private devContainerComponentInserter; | ||
find(devfileContext: DevfileContext, injectDefaultComponent?: string, defaultComponentImage?: string): Promise<V1alpha2DevWorkspaceSpecTemplateComponents | undefined>; | ||
} |
@@ -56,2 +56,3 @@ "use strict"; | ||
var inversify_1 = require("inversify"); | ||
var dev_container_component_inserter_1 = require("./dev-container-component-inserter"); | ||
/** | ||
@@ -63,13 +64,22 @@ * Need to find dev container from main dev workspace | ||
} | ||
DevContainerComponentFinder.prototype.find = function (devfileContext) { | ||
var _a, _b, _c; | ||
DevContainerComponentFinder.prototype.find = function (devfileContext, injectDefaultComponent, defaultComponentImage) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var devComponents; | ||
return __generator(this, function (_d) { | ||
devComponents = (_c = (_b = (_a = devfileContext.devWorkspace.spec) === null || _a === void 0 ? void 0 : _a.template) === null || _b === void 0 ? void 0 : _b.components) === null || _c === void 0 ? void 0 : _c.filter(function (component) { return component.container; }).filter( | ||
var devComponents, devComponents_1; | ||
return __generator(this, function (_e) { | ||
// if a devfile contains a parent, we should not add a default dev container | ||
if ((_a = devfileContext.devfile) === null || _a === void 0 ? void 0 : _a.parent) { | ||
return [2 /*return*/, undefined]; | ||
} | ||
devComponents = (_d = (_c = (_b = devfileContext.devWorkspace.spec) === null || _b === void 0 ? void 0 : _b.template) === null || _c === void 0 ? void 0 : _c.components) === null || _d === void 0 ? void 0 : _d.filter(function (component) { return component.container; }).filter( | ||
// we should ignore component that do not mount the sources | ||
function (component) { return component.container && component.container.mountSources !== false; }); | ||
// only one, fine, else error | ||
if (!devComponents || devComponents.length === 0) { | ||
throw new Error('Not able to find any dev container component in DevWorkspace'); | ||
// do not inject a default component if injectDefaultComponent parameter is false | ||
if (!injectDefaultComponent || injectDefaultComponent !== 'true') { | ||
return [2 /*return*/, undefined]; | ||
} | ||
this.devContainerComponentInserter.insert(devfileContext, defaultComponentImage); | ||
devComponents_1 = devfileContext.devWorkspace.spec.template.components.filter(function (component) { return component.container; }); | ||
return [2 /*return*/, devComponents_1[0]]; | ||
} | ||
@@ -87,2 +97,5 @@ else if (devComponents.length === 1) { | ||
}; | ||
__decorate([ | ||
(0, inversify_1.inject)(dev_container_component_inserter_1.DevContainerComponentInserter) | ||
], DevContainerComponentFinder.prototype, "devContainerComponentInserter"); | ||
DevContainerComponentFinder = __decorate([ | ||
@@ -89,0 +102,0 @@ (0, inversify_1.injectable)() |
@@ -15,6 +15,8 @@ "use strict"; | ||
var dev_container_component_finder_1 = require("./dev-container-component-finder"); | ||
var dev_container_component_inserter_1 = require("./dev-container-component-inserter"); | ||
var devfileModule = new inversify_1.ContainerModule(function (bind) { | ||
bind(dev_container_component_finder_1.DevContainerComponentFinder).toSelf().inSingletonScope(); | ||
bind(dev_container_component_inserter_1.DevContainerComponentInserter).toSelf().inSingletonScope(); | ||
}); | ||
exports.devfileModule = devfileModule; | ||
//# sourceMappingURL=devfile-module.js.map |
@@ -12,6 +12,6 @@ /********************************************************************** | ||
export declare class Generate { | ||
static readonly MERGE_CONTRIBUTION = "controller.devfile.io/merge-contribution"; | ||
private devContainerComponentFinder; | ||
generate(devfileContent: string, editorContent: string, outputFile?: string): Promise<DevfileContext>; | ||
generateContent(devfileContent: string, editorContent: string): Promise<DevfileContext>; | ||
generate(devfileContent: string, editorContent: string, outputFile?: string, injectDefaultComponent?: string, defaultComponentImage?: string): Promise<DevfileContext>; | ||
generateContent(devfileContent: string, editorContent: string, injectDefaultComponent?: string, defaultComponentImage?: string): Promise<DevfileContext>; | ||
private createDevWorkspaceMetadata; | ||
} |
@@ -81,4 +81,3 @@ "use strict"; | ||
} | ||
Generate_1 = Generate; | ||
Generate.prototype.generate = function (devfileContent, editorContent, outputFile) { | ||
Generate.prototype.generate = function (devfileContent, editorContent, outputFile, injectDefaultComponent, defaultComponentImage) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -88,3 +87,3 @@ var context, allContentArray, generatedContent; | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.generateContent(devfileContent, editorContent)]; | ||
case 0: return [4 /*yield*/, this.generateContent(devfileContent, editorContent, injectDefaultComponent, defaultComponentImage)]; | ||
case 1: | ||
@@ -107,5 +106,5 @@ context = _a.sent(); | ||
}; | ||
Generate.prototype.generateContent = function (devfileContent, editorContent) { | ||
Generate.prototype.generateContent = function (devfileContent, editorContent, injectDefaultComponent, defaultComponentImage) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var devfile, suffix, editorDevfile, metadata, editorDevWorkspaceTemplate, devfileMetadata, devfileCopy, editorSpecContribution, devWorkspace, devWorkspaceTemplates, context, devContainer, devContainerAttributes; | ||
var devfile, suffix, editorDevfile, metadata, editorDevWorkspaceTemplate, devfileMetadata, devfileCopy, editorSpecContribution, devWorkspace, devWorkspaceTemplates, context; | ||
return __generator(this, function (_a) { | ||
@@ -117,3 +116,3 @@ switch (_a.label) { | ||
editorDevfile = jsYaml.load(editorContent); | ||
metadata = editorDevfile.metadata; | ||
metadata = this.createDevWorkspaceMetadata(editorDevfile); | ||
// add sufix | ||
@@ -129,3 +128,3 @@ metadata.name = metadata.name + "-" + suffix; | ||
}; | ||
devfileMetadata = devfile.metadata; | ||
devfileMetadata = this.createDevWorkspaceMetadata(devfile, true); | ||
devfileCopy = Object.assign({}, devfile); | ||
@@ -146,2 +145,3 @@ delete devfileCopy.schemaVersion; | ||
started: true, | ||
routingClass: 'che', | ||
template: devfileCopy, | ||
@@ -158,14 +158,7 @@ contributions: [editorSpecContribution] | ||
}; | ||
return [4 /*yield*/, this.devContainerComponentFinder.find(context)]; | ||
// find devContainer component, add a default one if not found | ||
return [4 /*yield*/, this.devContainerComponentFinder.find(context, injectDefaultComponent, defaultComponentImage)]; | ||
case 1: | ||
devContainer = _a.sent(); | ||
devContainerAttributes = devContainer.attributes; | ||
if (!devContainerAttributes) { | ||
devContainerAttributes = {}; | ||
devContainerAttributes[Generate_1.MERGE_CONTRIBUTION] = true; | ||
devContainer.attributes = devContainerAttributes; | ||
} | ||
else { | ||
devContainerAttributes[Generate_1.MERGE_CONTRIBUTION] = true; | ||
} | ||
// find devContainer component, add a default one if not found | ||
_a.sent(); | ||
return [2 /*return*/, context]; | ||
@@ -176,8 +169,23 @@ } | ||
}; | ||
var Generate_1; | ||
Generate.MERGE_CONTRIBUTION = 'controller.devfile.io/merge-contribution'; | ||
Generate.prototype.createDevWorkspaceMetadata = function (devfile, addDevfileContent) { | ||
if (addDevfileContent === void 0) { addDevfileContent = false; } | ||
var devWorkspaceMetadata = {}; | ||
var devfileMetadata = devfile.metadata; | ||
if (devfileMetadata.name) { | ||
devWorkspaceMetadata.name = devfileMetadata.name; | ||
} | ||
if (devfileMetadata.generateName) { | ||
devWorkspaceMetadata.generateName = devfileMetadata.generateName; | ||
} | ||
if (addDevfileContent) { | ||
devWorkspaceMetadata.annotations = { | ||
'che.eclipse.org/devfile': jsYaml.dump(devfile) | ||
}; | ||
} | ||
return devWorkspaceMetadata; | ||
}; | ||
__decorate([ | ||
(0, inversify_1.inject)(dev_container_component_finder_1.DevContainerComponentFinder) | ||
], Generate.prototype, "devContainerComponentFinder"); | ||
Generate = Generate_1 = __decorate([ | ||
Generate = __decorate([ | ||
(0, inversify_1.injectable)() | ||
@@ -184,0 +192,0 @@ ], Generate); |
@@ -15,6 +15,8 @@ "use strict"; | ||
var github_resolver_1 = require("./github-resolver"); | ||
var types_1 = require("../types"); | ||
var Resolver = types_1.TYPES.Resolver; | ||
var githubModule = new inversify_1.ContainerModule(function (bind) { | ||
bind(github_resolver_1.GithubResolver).toSelf().inSingletonScope(); | ||
bind(Resolver).to(github_resolver_1.GithubResolver).inSingletonScope(); | ||
}); | ||
exports.githubModule = githubModule; | ||
//# sourceMappingURL=github-module.js.map |
@@ -10,10 +10,9 @@ /********************************************************************** | ||
***********************************************************************/ | ||
import { GithubUrl } from './github-url'; | ||
/** | ||
* Provides a github URL object allowing to interact | ||
*/ | ||
export declare class GithubResolver { | ||
import { Url } from '../resolve/url'; | ||
import { Resolver } from '../resolve/resolver'; | ||
export declare class GithubResolver implements Resolver { | ||
static readonly GITHUB_URL_PATTERN: RegExp; | ||
resolve(link: string): GithubUrl; | ||
getGroup(match: RegExpExecArray, groupName: string, defaultValue?: string): string; | ||
isValid(url: string): boolean; | ||
resolve(link: string): Url; | ||
private getGroup; | ||
} |
@@ -21,5 +21,2 @@ "use strict"; | ||
var inversify_1 = require("inversify"); | ||
/** | ||
* Provides a github URL object allowing to interact | ||
*/ | ||
var GithubResolver = /** @class */ (function () { | ||
@@ -29,2 +26,5 @@ function GithubResolver() { | ||
GithubResolver_1 = GithubResolver; | ||
GithubResolver.prototype.isValid = function (url) { | ||
return GithubResolver_1.GITHUB_URL_PATTERN.test(url); | ||
}; | ||
GithubResolver.prototype.resolve = function (link) { | ||
@@ -35,7 +35,12 @@ var match = GithubResolver_1.GITHUB_URL_PATTERN.exec(link); | ||
} | ||
var scheme = this.getGroup(match, 'scheme'); | ||
var hostName = this.getGroup(match, 'host'); | ||
var repoUser = this.getGroup(match, 'repoUser'); | ||
var repoName = this.getGroup(match, 'repoName'); | ||
if (/^[\w-][\w.-]*?\.git$/.test(repoName)) { | ||
repoName = repoName.substring(0, repoName.length - 4); | ||
} | ||
var branchName = this.getGroup(match, 'branchName', 'HEAD'); | ||
var subFolder = this.getGroup(match, 'subFolder'); | ||
return new github_url_1.GithubUrl(repoUser, repoName, branchName, subFolder); | ||
return new github_url_1.GithubUrl(scheme, hostName, repoUser, repoName, branchName, subFolder); | ||
}; | ||
@@ -50,3 +55,3 @@ GithubResolver.prototype.getGroup = function (match, groupName, defaultValue) { | ||
// eslint-disable-next-line max-len | ||
GithubResolver.GITHUB_URL_PATTERN = /^(?:http)(?:s)?(?:\:\/\/)github\.com\/(?<repoUser>[^\/]+)\/(?<repoName>[^\/]+)((\/)|(?:\/(blob|tree)\/(?<branchName>[^\/]+)(?:\/(?<subFolder>.*))?))?$/; | ||
GithubResolver.GITHUB_URL_PATTERN = /^(?<scheme>https?):\/\/(?<host>github(\..+)?\.[^\/]+)\/(?<repoUser>[^\/]+)\/(?<repoName>[^\/]+)((\/)|\/(blob|tree)\/(?<branchName>[^\/]+)(?:\/(?<subFolder>.*))?)?$/; | ||
GithubResolver = GithubResolver_1 = __decorate([ | ||
@@ -53,0 +58,0 @@ (0, inversify_1.injectable)() |
@@ -10,6 +10,6 @@ /********************************************************************** | ||
***********************************************************************/ | ||
/** | ||
* Provides helper methods on top of github URL to get for example raw content of get relative links | ||
*/ | ||
export declare class GithubUrl { | ||
import { Url } from '../resolve/url'; | ||
export declare class GithubUrl implements Url { | ||
private readonly scheme; | ||
private readonly hostName; | ||
private readonly repoUser; | ||
@@ -19,4 +19,3 @@ private readonly repoName; | ||
private readonly subFolder; | ||
static readonly RAW_LINK = "https://raw.githubusercontent.com"; | ||
constructor(repoUser: string, repoName: string, branchName: string, subFolder: string); | ||
constructor(scheme: string, hostName: string, repoUser: string, repoName: string, branchName: string, subFolder: string); | ||
/** | ||
@@ -23,0 +22,0 @@ * Provides the raw link to the given path based on the current repository information |
@@ -13,7 +13,6 @@ "use strict"; | ||
exports.GithubUrl = void 0; | ||
/** | ||
* Provides helper methods on top of github URL to get for example raw content of get relative links | ||
*/ | ||
var GithubUrl = /** @class */ (function () { | ||
function GithubUrl(repoUser, repoName, branchName, subFolder) { | ||
function GithubUrl(scheme, hostName, repoUser, repoName, branchName, subFolder) { | ||
this.scheme = scheme; | ||
this.hostName = hostName; | ||
this.repoUser = repoUser; | ||
@@ -28,9 +27,10 @@ this.repoName = repoName; | ||
GithubUrl.prototype.getContentUrl = function (path) { | ||
return GithubUrl.RAW_LINK + "/" + this.repoUser + "/" + this.repoName + "/" + this.branchName + "/" + path; | ||
var hostName = this.hostName === 'github.com' ? 'githubusercontent.com' : this.hostName; | ||
return this.scheme + "://raw." + hostName + "/" + this.repoUser + "/" + this.repoName + "/" + this.branchName + "/" + path; | ||
}; | ||
GithubUrl.prototype.getUrl = function () { | ||
return "https://github.com/" + this.repoUser + "/" + this.repoName + "/tree/" + this.branchName + "/" + this.subFolder; | ||
return this.scheme + "://" + this.hostName + "/" + this.repoUser + "/" + this.repoName + "/tree/" + this.branchName + "/" + this.subFolder; | ||
}; | ||
GithubUrl.prototype.getCloneUrl = function () { | ||
return "https://github.com/" + this.repoUser + "/" + this.repoName + ".git"; | ||
return this.scheme + "://" + this.hostName + "/" + this.repoUser + "/" + this.repoName + ".git"; | ||
}; | ||
@@ -43,4 +43,2 @@ GithubUrl.prototype.getRepoName = function () { | ||
}; | ||
// raw link | ||
GithubUrl.RAW_LINK = 'https://raw.githubusercontent.com'; | ||
return GithubUrl; | ||
@@ -47,0 +45,0 @@ }()); |
@@ -54,3 +54,6 @@ "use strict"; | ||
var github_module_1 = require("../github/github-module"); | ||
var resolve_module_1 = require("../resolve/resolve-module"); | ||
var plugin_registry_module_1 = require("../plugin-registry/plugin-registry-module"); | ||
var bitbucket_module_1 = require("../bitbucket/bitbucket-module"); | ||
var bitbucket_server_module_1 = require("../bitbucket-server/bitbucket-server-module"); | ||
/** | ||
@@ -69,2 +72,5 @@ * Manage all bindings for inversify | ||
this.container.load(github_module_1.githubModule); | ||
this.container.load(bitbucket_module_1.bitbucketModule); | ||
this.container.load(bitbucket_server_module_1.bitbucketServerModule); | ||
this.container.load(resolve_module_1.resolveModule); | ||
this.container.load(plugin_registry_module_1.pluginRegistryModule); | ||
@@ -71,0 +77,0 @@ this.container.bind(Symbol["for"]('AxiosInstance')).toConstantValue(options.axiosInstance); |
@@ -30,2 +30,4 @@ /********************************************************************** | ||
}[]; | ||
injectDefaultComponent?: string; | ||
defaultComponentImage?: string; | ||
}, axiosInstance: axios.AxiosInstance): Promise<DevfileContext>; | ||
@@ -32,0 +34,0 @@ replaceIfExistingProjects(devfileContent: string, projects: { |
@@ -71,3 +71,2 @@ "use strict"; | ||
var generate_1 = require("./generate"); | ||
var github_resolver_1 = require("./github/github-resolver"); | ||
var jsYaml = __importStar(require("js-yaml")); | ||
@@ -77,2 +76,3 @@ var inversify_binding_1 = require("./inversify/inversify-binding"); | ||
var plugin_registry_resolver_1 = require("./plugin-registry/plugin-registry-resolver"); | ||
var git_url_resolver_1 = require("./resolve/git-url-resolver"); | ||
var Main = /** @class */ (function () { | ||
@@ -88,3 +88,3 @@ /** | ||
return __awaiter(this, void 0, void 0, function () { | ||
var pluginRegistryUrl, inversifyBinbding, container, devfileContent, editorContent, githubResolver, githubUrl, devfileParsed, editorDevfile, generate; | ||
var pluginRegistryUrl, inversifyBinbding, container, devfileContent, editorContent, resolver, url, devfileParsed, editorDevfile, generate; | ||
return __generator(this, function (_a) { | ||
@@ -115,5 +115,5 @@ switch (_a.label) { | ||
if (!params.devfileUrl) return [3 /*break*/, 3]; | ||
githubResolver = container.get(github_resolver_1.GithubResolver); | ||
githubUrl = githubResolver.resolve(params.devfileUrl); | ||
return [4 /*yield*/, container.get(url_fetcher_1.UrlFetcher).fetchText(githubUrl.getContentUrl('devfile.yaml'))]; | ||
resolver = container.get(git_url_resolver_1.GitUrlResolver); | ||
url = resolver.resolve(params.devfileUrl); | ||
return [4 /*yield*/, container.get(url_fetcher_1.UrlFetcher).fetchText(url.getContentUrl('devfile.yaml'))]; | ||
case 2: | ||
@@ -128,6 +128,6 @@ // user devfile | ||
{ | ||
name: githubUrl.getRepoName(), | ||
name: url.getRepoName(), | ||
git: { | ||
remotes: { origin: githubUrl.getCloneUrl() }, | ||
checkoutFrom: { revision: githubUrl.getBranchName() } | ||
remotes: { origin: url.getCloneUrl() }, | ||
checkoutFrom: { revision: url.getBranchName() } | ||
} | ||
@@ -168,3 +168,3 @@ }, | ||
generate = container.get(generate_1.Generate); | ||
return [2 /*return*/, generate.generate(devfileContent, editorContent, params.outputFile)]; | ||
return [2 /*return*/, generate.generate(devfileContent, editorContent, params.outputFile, params.injectDefaultComponent, params.defaultComponentImage)]; | ||
} | ||
@@ -202,3 +202,3 @@ }); | ||
return __awaiter(this, void 0, void 0, function () { | ||
var devfilePath, devfileUrl, outputFile, editorPath, pluginRegistryUrl, editorEntry, projects, args, error_1; | ||
var devfilePath, devfileUrl, outputFile, editorPath, pluginRegistryUrl, editorEntry, injectDefaultComponent, defaultComponentImage, projects, args, error_1; | ||
return __generator(this, function (_a) { | ||
@@ -234,2 +234,8 @@ switch (_a.label) { | ||
} | ||
if (arg.startsWith('--injectDefaultComponent:')) { | ||
injectDefaultComponent = arg.substring('--injectDefaultComponent:'.length); | ||
} | ||
if (arg.startsWith('--defaultComponentImage:')) { | ||
defaultComponentImage = arg.substring('--defaultComponentImage:'.length); | ||
} | ||
}); | ||
@@ -255,3 +261,5 @@ _a.label = 1; | ||
editorEntry: editorEntry, | ||
projects: projects | ||
projects: projects, | ||
injectDefaultComponent: injectDefaultComponent, | ||
defaultComponentImage: defaultComponentImage | ||
}, axios["default"])]; | ||
@@ -258,0 +266,0 @@ case 2: |
@@ -83,3 +83,3 @@ "use strict"; | ||
} | ||
// FQN id (like eclipse/che-theia/next) | ||
// FQN id (like che-incubator/che-code/next) | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -86,0 +86,0 @@ PluginRegistryResolver.prototype.loadDevfilePlugin = function (devfileId) { |
{ | ||
"name": "@eclipse-che/che-devworkspace-generator", | ||
"version": "0.0.1-96cdbb4", | ||
"version": "0.0.1-99986b8", | ||
"private": false, | ||
@@ -5,0 +5,0 @@ "description": "Generates DevWorkspaces by transforming existing devfiles", |
## DevWorkspace Generator | ||
The library is used by Devfile registry component to generate the DevWorkspace components and DevWorkspace templates. | ||
The library is used by Devfile registry component to generate the DevWorkspace components and DevWorkspace templates. It requires editor definitions from the | ||
[che-plugin-registry](https://github.com/eclipse-che/che-plugin-registry/). | ||
## How to use the library | ||
The library could be used as a standalone library. | ||
The library can be used as a standalone library. | ||
@@ -12,18 +13,45 @@ ``` | ||
OPTIONS | ||
--devfile-path path to the devfile.yaml file | ||
--devfile-url URL to the git repository that contains devfile.yaml | ||
--plugin-registry-url URL to the plugin registry that contains an editor's definition | ||
--editor-entry editor's ID | ||
--editor-path: path to the editor's devfile.yaml file | ||
--output-file path to the file where the generated content will be stored | ||
--project. describes project entry | ||
--devfile-url: URL to the git repository that contains devfile.yaml | ||
or | ||
--devfile-path: path to the devfile.yaml file | ||
EXAMPLE | ||
--plugin-registry-url: URL to the plugin registry that contains editor definitions (devfile.yaml) | ||
--editor-entry: editor ID, found on the <plugin-registry-url>, to resolve the devfile.yaml | ||
or | ||
--editor-path: local file path of the editor devfile.yaml | ||
$ node lib/entrypoint.js --devfile-url:https://github.com/che-samples/java-spring-petclinic/tree/main --editor-entry:che-incubator/che-code/insiders --plugin-registry-url:https://che-plugin-registry-main.surge.sh/v3/ --output-file:/tmp/all-in-one.yaml` | ||
--output-file: local file path for the generated devworkspace yaml | ||
--project.<project-name> local file path for the sample project zip (for airgapped/offline registry builds) | ||
--injectDefaultComponent: inject a default dev container component if no component is defined in the devfile and it doesn't provide a parent, the value can be true or false, default is false | ||
--defaultComponentImage: image to use for the default dev container component that will be injected if no componetn is defined in the devfile and it doesn't provide a parent devfile, default is quay.io/devfile/universal-developer-image:ubi8-latest | ||
EXAMPLES | ||
# online example, using editor definition from https://che-plugin-registry-main.surge.sh/ | ||
$ node lib/entrypoint.js \ | ||
--devfile-url:https://github.com/che-samples/java-spring-petclinic/tree/main \ | ||
--plugin-registry-url:https://che-plugin-registry-main.surge.sh/v3/ \ | ||
--editor-entry:che-incubator/che-code/latest \ | ||
--output-file:/tmp/devworkspace-che-code-latest.yaml \ | ||
--injectDefaultComponent:true \ | ||
--defaultComponentImage:registry.access.redhat.com/ubi8/openjdk-11:latest | ||
# offline example with devfile.yaml files and zipped project available locally | ||
$ node lib/entrypoint.js \ | ||
--devfile-path:/remote-source/python-hello-world/app/devfile.yaml \ | ||
--editor-path:/build/plugins/che-incubator/che-code/latest/devfile.yaml \ | ||
--output-file:./devfiles/python__python-hello-world/devworkspace-che-code-latest.yaml \ | ||
--project.python-hello-world='{{_INTERNAL_URL_}}/resources/v2/python-hello-world.zip' | ||
``` | ||
The file `/tmp/all-in-one.yaml` contains a DevWorkspace based on the repository devfile and a Che-Code DevWorkspaceTemplate. | ||
If DevWorkspace engine is available on the cluster, the following command will create a DevWorkspace: | ||
The output file `devworkspace-che-code-latest.yaml` contains a DevWorkspace based on the repository devfile and a Che-Code DevWorkspaceTemplate. | ||
`$ kubectl apply -f /tmp/all-in-one.yaml` | ||
If the DevWorkspace engine is installed on the cluster, the following command will create a DevWorkspace: | ||
`$ kubectl apply -f /tmp/devworkspace-che-code-latest.yaml` |
@@ -13,3 +13,4 @@ /********************************************************************** | ||
import { V1alpha2DevWorkspaceSpecTemplateComponents } from '@devfile/api'; | ||
import { injectable } from 'inversify'; | ||
import { inject, injectable } from 'inversify'; | ||
import { DevContainerComponentInserter } from './dev-container-component-inserter'; | ||
@@ -21,3 +22,14 @@ /** | ||
export class DevContainerComponentFinder { | ||
async find(devfileContext: DevfileContext): Promise<V1alpha2DevWorkspaceSpecTemplateComponents | undefined> { | ||
@inject(DevContainerComponentInserter) | ||
private devContainerComponentInserter: DevContainerComponentInserter; | ||
async find( | ||
devfileContext: DevfileContext, | ||
injectDefaultComponent?: string, | ||
defaultComponentImage?: string | ||
): Promise<V1alpha2DevWorkspaceSpecTemplateComponents | undefined> { | ||
// if a devfile contains a parent, we should not add a default dev container | ||
if (devfileContext.devfile?.parent) { | ||
return undefined; | ||
} | ||
// search in main devWorkspace | ||
@@ -31,5 +43,12 @@ const devComponents = devfileContext.devWorkspace.spec?.template?.components | ||
// only one, fine, else error | ||
if (!devComponents || devComponents.length === 0) { | ||
throw new Error('Not able to find any dev container component in DevWorkspace'); | ||
// do not inject a default component if injectDefaultComponent parameter is false | ||
if (!injectDefaultComponent || injectDefaultComponent !== 'true') { | ||
return undefined; | ||
} | ||
this.devContainerComponentInserter.insert(devfileContext, defaultComponentImage); | ||
let devComponents = devfileContext.devWorkspace.spec.template.components.filter(component => component.container); | ||
return devComponents[0]; | ||
} else if (devComponents.length === 1) { | ||
@@ -36,0 +55,0 @@ return devComponents[0]; |
@@ -13,7 +13,9 @@ /********************************************************************** | ||
import { DevContainerComponentFinder } from './dev-container-component-finder'; | ||
import { DevContainerComponentInserter } from './dev-container-component-inserter'; | ||
const devfileModule = new ContainerModule((bind: interfaces.Bind) => { | ||
bind(DevContainerComponentFinder).toSelf().inSingletonScope(); | ||
bind(DevContainerComponentInserter).toSelf().inSingletonScope(); | ||
}); | ||
export { devfileModule }; |
@@ -12,5 +12,7 @@ /********************************************************************** | ||
import { | ||
V221Devfile, | ||
V221DevfileMetadata, | ||
V1alpha2DevWorkspace, | ||
V1alpha2DevWorkspaceMetadata, | ||
V1alpha2DevWorkspaceSpecContributions, | ||
V1alpha2DevWorkspaceSpecTemplateComponents, | ||
V1alpha2DevWorkspaceTemplate, | ||
@@ -25,11 +27,26 @@ V1alpha2DevWorkspaceTemplateSpec, | ||
type DevfileLike = V221Devfile & { | ||
metadata: V221DevfileMetadata & { | ||
generateName?: string; | ||
}; | ||
}; | ||
@injectable() | ||
export class Generate { | ||
static readonly MERGE_CONTRIBUTION = 'controller.devfile.io/merge-contribution'; | ||
@inject(DevContainerComponentFinder) | ||
private devContainerComponentFinder: DevContainerComponentFinder; | ||
async generate(devfileContent: string, editorContent: string, outputFile?: string): Promise<DevfileContext> { | ||
const context = await this.generateContent(devfileContent, editorContent); | ||
async generate( | ||
devfileContent: string, | ||
editorContent: string, | ||
outputFile?: string, | ||
injectDefaultComponent?: string, | ||
defaultComponentImage?: string | ||
): Promise<DevfileContext> { | ||
const context = await this.generateContent( | ||
devfileContent, | ||
editorContent, | ||
injectDefaultComponent, | ||
defaultComponentImage | ||
); | ||
@@ -51,3 +68,8 @@ // write the result | ||
async generateContent(devfileContent: string, editorContent: string): Promise<DevfileContext> { | ||
async generateContent( | ||
devfileContent: string, | ||
editorContent: string, | ||
injectDefaultComponent?: string, | ||
defaultComponentImage?: string | ||
): Promise<DevfileContext> { | ||
const devfile = jsYaml.load(devfileContent); | ||
@@ -63,3 +85,3 @@ | ||
// transform it into a devWorkspace template | ||
const metadata = editorDevfile.metadata; | ||
const metadata = this.createDevWorkspaceMetadata(editorDevfile); | ||
// add sufix | ||
@@ -77,3 +99,3 @@ metadata.name = `${metadata.name}-${suffix}`; | ||
// transform it into a devWorkspace | ||
const devfileMetadata = devfile.metadata; | ||
const devfileMetadata = this.createDevWorkspaceMetadata(devfile, true); | ||
const devfileCopy = Object.assign({}, devfile); | ||
@@ -94,2 +116,3 @@ delete devfileCopy.schemaVersion; | ||
started: true, | ||
routingClass: 'che', | ||
template: devfileCopy, | ||
@@ -110,17 +133,26 @@ contributions: [editorSpecContribution], | ||
// grab container where to inject controller.devfile.io/merge-contribution attribute | ||
let devContainer: V1alpha2DevWorkspaceSpecTemplateComponents = await this.devContainerComponentFinder.find(context); | ||
// find devContainer component, add a default one if not found | ||
await this.devContainerComponentFinder.find(context, injectDefaultComponent, defaultComponentImage); | ||
// add attributes | ||
let devContainerAttributes = devContainer.attributes; | ||
if (!devContainerAttributes) { | ||
devContainerAttributes = {}; | ||
devContainerAttributes[Generate.MERGE_CONTRIBUTION] = true; | ||
devContainer.attributes = devContainerAttributes; | ||
} else { | ||
devContainerAttributes[Generate.MERGE_CONTRIBUTION] = true; | ||
return context; | ||
} | ||
private createDevWorkspaceMetadata(devfile: DevfileLike, addDevfileContent = false): V1alpha2DevWorkspaceMetadata { | ||
const devWorkspaceMetadata = {} as V1alpha2DevWorkspaceMetadata; | ||
const devfileMetadata = devfile.metadata; | ||
if (devfileMetadata.name) { | ||
devWorkspaceMetadata.name = devfileMetadata.name; | ||
} | ||
if (devfileMetadata.generateName) { | ||
devWorkspaceMetadata.generateName = devfileMetadata.generateName; | ||
} | ||
if (addDevfileContent) { | ||
devWorkspaceMetadata.annotations = { | ||
'che.eclipse.org/devfile': jsYaml.dump(devfile), | ||
}; | ||
} | ||
return context; | ||
return devWorkspaceMetadata; | ||
} | ||
} |
@@ -13,7 +13,10 @@ /********************************************************************** | ||
import { GithubResolver } from './github-resolver'; | ||
import { TYPES } from '../types'; | ||
const { Resolver } = TYPES; | ||
const githubModule = new ContainerModule((bind: interfaces.Bind) => { | ||
bind(GithubResolver).toSelf().inSingletonScope(); | ||
bind(Resolver).to(GithubResolver).inSingletonScope(); | ||
}); | ||
export { githubModule }; |
@@ -13,13 +13,16 @@ /********************************************************************** | ||
import { injectable } from 'inversify'; | ||
import { Url } from '../resolve/url'; | ||
import { Resolver } from '../resolve/resolver'; | ||
/** | ||
* Provides a github URL object allowing to interact | ||
*/ | ||
@injectable() | ||
export class GithubResolver { | ||
export class GithubResolver implements Resolver { | ||
// eslint-disable-next-line max-len | ||
static readonly GITHUB_URL_PATTERN = | ||
/^(?:http)(?:s)?(?:\:\/\/)github\.com\/(?<repoUser>[^\/]+)\/(?<repoName>[^\/]+)((\/)|(?:\/(blob|tree)\/(?<branchName>[^\/]+)(?:\/(?<subFolder>.*))?))?$/; | ||
/^(?<scheme>https?):\/\/(?<host>github(\..+)?\.[^\/]+)\/(?<repoUser>[^\/]+)\/(?<repoName>[^\/]+)((\/)|\/(blob|tree)\/(?<branchName>[^\/]+)(?:\/(?<subFolder>.*))?)?$/; | ||
resolve(link: string): GithubUrl { | ||
isValid(url: string): boolean { | ||
return GithubResolver.GITHUB_URL_PATTERN.test(url); | ||
} | ||
resolve(link: string): Url { | ||
const match = GithubResolver.GITHUB_URL_PATTERN.exec(link); | ||
@@ -29,10 +32,15 @@ if (!match) { | ||
} | ||
const scheme = this.getGroup(match, 'scheme'); | ||
const hostName = this.getGroup(match, 'host'); | ||
const repoUser = this.getGroup(match, 'repoUser'); | ||
const repoName = this.getGroup(match, 'repoName'); | ||
let repoName = this.getGroup(match, 'repoName'); | ||
if (/^[\w-][\w.-]*?\.git$/.test(repoName)) { | ||
repoName = repoName.substring(0, repoName.length - 4); | ||
} | ||
const branchName = this.getGroup(match, 'branchName', 'HEAD'); | ||
const subFolder = this.getGroup(match, 'subFolder'); | ||
return new GithubUrl(repoUser, repoName, branchName, subFolder); | ||
return new GithubUrl(scheme, hostName, repoUser, repoName, branchName, subFolder); | ||
} | ||
getGroup(match: RegExpExecArray, groupName: string, defaultValue?: string) { | ||
private getGroup(match: RegExpExecArray, groupName: string, defaultValue?: string) { | ||
if (match.groups && match.groups[groupName]) { | ||
@@ -39,0 +47,0 @@ return match.groups[groupName]; |
@@ -11,10 +11,8 @@ /********************************************************************** | ||
/** | ||
* Provides helper methods on top of github URL to get for example raw content of get relative links | ||
*/ | ||
export class GithubUrl { | ||
// raw link | ||
static readonly RAW_LINK = 'https://raw.githubusercontent.com'; | ||
import { Url } from '../resolve/url'; | ||
export class GithubUrl implements Url { | ||
constructor( | ||
private readonly scheme: string, | ||
private readonly hostName: string, | ||
private readonly repoUser: string, | ||
@@ -30,11 +28,12 @@ private readonly repoName: string, | ||
getContentUrl(path: string): string { | ||
return `${GithubUrl.RAW_LINK}/${this.repoUser}/${this.repoName}/${this.branchName}/${path}`; | ||
const hostName = this.hostName === 'github.com' ? 'githubusercontent.com' : this.hostName; | ||
return `${this.scheme}://raw.${hostName}/${this.repoUser}/${this.repoName}/${this.branchName}/${path}`; | ||
} | ||
getUrl(): string { | ||
return `https://github.com/${this.repoUser}/${this.repoName}/tree/${this.branchName}/${this.subFolder}`; | ||
return `${this.scheme}://${this.hostName}/${this.repoUser}/${this.repoName}/tree/${this.branchName}/${this.subFolder}`; | ||
} | ||
getCloneUrl(): string { | ||
return `https://github.com/${this.repoUser}/${this.repoName}.git`; | ||
return `${this.scheme}://${this.hostName}/${this.repoUser}/${this.repoName}.git`; | ||
} | ||
@@ -41,0 +40,0 @@ |
@@ -17,3 +17,6 @@ /********************************************************************** | ||
import { githubModule } from '../github/github-module'; | ||
import { resolveModule } from '../resolve/resolve-module'; | ||
import { pluginRegistryModule } from '../plugin-registry/plugin-registry-module'; | ||
import { bitbucketModule } from '../bitbucket/bitbucket-module'; | ||
import { bitbucketServerModule } from '../bitbucket-server/bitbucket-server-module'; | ||
@@ -32,2 +35,5 @@ /** | ||
this.container.load(githubModule); | ||
this.container.load(bitbucketModule); | ||
this.container.load(bitbucketServerModule); | ||
this.container.load(resolveModule); | ||
this.container.load(pluginRegistryModule); | ||
@@ -34,0 +40,0 @@ |
@@ -21,2 +21,3 @@ /********************************************************************** | ||
import { DevfileContext } from './api/devfile-context'; | ||
import { GitUrlResolver } from './resolve/git-url-resolver'; | ||
@@ -42,2 +43,4 @@ export class Main { | ||
projects: { name: string; location: string }[]; | ||
injectDefaultComponent?: string; | ||
defaultComponentImage?: string; | ||
}, | ||
@@ -72,8 +75,8 @@ axiosInstance: axios.AxiosInstance | ||
// gets the github URL | ||
// gets the repo URL | ||
if (params.devfileUrl) { | ||
const githubResolver = container.get(GithubResolver); | ||
const githubUrl = githubResolver.resolve(params.devfileUrl); | ||
const resolver = container.get(GitUrlResolver); | ||
const url = resolver.resolve(params.devfileUrl); | ||
// user devfile | ||
devfileContent = await container.get(UrlFetcher).fetchText(githubUrl.getContentUrl('devfile.yaml')); | ||
devfileContent = await container.get(UrlFetcher).fetchText(url.getContentUrl('devfile.yaml')); | ||
@@ -88,6 +91,6 @@ // load content | ||
{ | ||
name: githubUrl.getRepoName(), | ||
name: url.getRepoName(), | ||
git: { | ||
remotes: { origin: githubUrl.getCloneUrl() }, | ||
checkoutFrom: { revision: githubUrl.getBranchName() }, | ||
remotes: { origin: url.getCloneUrl() }, | ||
checkoutFrom: { revision: url.getBranchName() }, | ||
}, | ||
@@ -119,3 +122,9 @@ }, | ||
const generate = container.get(Generate); | ||
return generate.generate(devfileContent, editorContent, params.outputFile); | ||
return generate.generate( | ||
devfileContent, | ||
editorContent, | ||
params.outputFile, | ||
params.injectDefaultComponent, | ||
params.defaultComponentImage | ||
); | ||
} | ||
@@ -157,2 +166,4 @@ | ||
let editorEntry: string | undefined; | ||
let injectDefaultComponent: string | undefined; | ||
let defaultComponentImage: string | undefined; | ||
const projects: { name: string; location: string }[] = []; | ||
@@ -187,2 +198,8 @@ | ||
} | ||
if (arg.startsWith('--injectDefaultComponent:')) { | ||
injectDefaultComponent = arg.substring('--injectDefaultComponent:'.length); | ||
} | ||
if (arg.startsWith('--defaultComponentImage:')) { | ||
defaultComponentImage = arg.substring('--defaultComponentImage:'.length); | ||
} | ||
}); | ||
@@ -209,2 +226,4 @@ | ||
projects, | ||
injectDefaultComponent, | ||
defaultComponentImage, | ||
}, | ||
@@ -211,0 +230,0 @@ axios.default |
@@ -29,3 +29,3 @@ /********************************************************************** | ||
// FQN id (like eclipse/che-theia/next) | ||
// FQN id (like che-incubator/che-code/next) | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -32,0 +32,0 @@ async loadDevfilePlugin(devfileId: string): Promise<any> { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 4 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 4 instances in 1 package
174269
106
3068
57