@eclipse-che/che-devworkspace-generator
Advanced tools
Comparing version 0.0.1-d7aefd7 to 0.0.1-ea73e8b
@@ -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 |
@@ -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,5 +87,6 @@ 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: | ||
context = _a.sent(); | ||
if (!outputFile) return [3 /*break*/, 3]; | ||
allContentArray = context.devWorkspaceTemplates.map(function (template) { return jsYaml.dump(template); }); | ||
@@ -98,2 +98,4 @@ allContentArray.push(jsYaml.dump(context.devWorkspace)); | ||
_a.sent(); | ||
_a.label = 3; | ||
case 3: | ||
console.log("DevWorkspace " + context.devWorkspaceTemplates[0].metadata.name + " was generated."); | ||
@@ -105,5 +107,5 @@ return [2 /*return*/, context]; | ||
}; | ||
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) { | ||
@@ -115,3 +117,3 @@ switch (_a.label) { | ||
editorDevfile = jsYaml.load(editorContent); | ||
metadata = editorDevfile.metadata; | ||
metadata = this.createDevWorkspaceMetadata(editorDevfile); | ||
// add sufix | ||
@@ -127,3 +129,3 @@ metadata.name = metadata.name + "-" + suffix; | ||
}; | ||
devfileMetadata = devfile.metadata; | ||
devfileMetadata = this.createDevWorkspaceMetadata(devfile, true); | ||
devfileCopy = Object.assign({}, devfile); | ||
@@ -144,2 +146,3 @@ delete devfileCopy.schemaVersion; | ||
started: true, | ||
routingClass: 'che', | ||
template: devfileCopy, | ||
@@ -156,14 +159,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]; | ||
@@ -174,8 +170,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)() | ||
@@ -182,0 +193,0 @@ ], Generate); |
@@ -33,2 +33,4 @@ "use strict"; | ||
} | ||
var scheme = this.getGroup(match, 'scheme'); | ||
var hostName = this.getGroup(match, 'host'); | ||
var repoUser = this.getGroup(match, 'repoUser'); | ||
@@ -38,3 +40,3 @@ var repoName = this.getGroup(match, 'repoName'); | ||
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); | ||
}; | ||
@@ -49,3 +51,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([ | ||
@@ -52,0 +54,0 @@ (0, inversify_1.injectable)() |
@@ -17,3 +17,5 @@ "use strict"; | ||
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 +30,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 +46,2 @@ GithubUrl.prototype.getRepoName = function () { | ||
}; | ||
// raw link | ||
GithubUrl.RAW_LINK = 'https://raw.githubusercontent.com'; | ||
return GithubUrl; | ||
@@ -47,0 +48,0 @@ }()); |
160
lib/main.js
@@ -77,52 +77,28 @@ "use strict"; | ||
var Main = /** @class */ (function () { | ||
/** | ||
* Default constructor. | ||
*/ | ||
function Main() { | ||
// no-op | ||
} | ||
Main.prototype.doStart = function () { | ||
// Generates a devfile context object based on params | ||
Main.prototype.generateDevfileContext = function (params, axiosInstance) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var devfilePath, devfileUrl, outputFile, editorPath, pluginRegistryUrl, editorEntry, projects, args, axiosInstance, inversifyBinbding, container, devfileContent, editorContent, githubResolver, githubUrl, devfileParsed, editorDevfile, generate; | ||
var pluginRegistryUrl, inversifyBinbding, container, devfileContent, editorContent, githubResolver, githubUrl, devfileParsed, editorDevfile, generate; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
projects = []; | ||
args = process.argv.slice(2); | ||
args.forEach(function (arg) { | ||
if (arg.startsWith('--devfile-path:')) { | ||
devfilePath = arg.substring('--devfile-path:'.length); | ||
} | ||
if (arg.startsWith('--devfile-url:')) { | ||
devfileUrl = arg.substring('--devfile-url:'.length); | ||
} | ||
if (arg.startsWith('--plugin-registry-url:')) { | ||
pluginRegistryUrl = arg.substring('--plugin-registry-url:'.length); | ||
} | ||
if (arg.startsWith('--editor-entry:')) { | ||
editorEntry = arg.substring('--editor-entry:'.length); | ||
} | ||
if (arg.startsWith('--editor-path:')) { | ||
editorPath = arg.substring('--editor-path:'.length); | ||
} | ||
if (arg.startsWith('--output-file:')) { | ||
outputFile = arg.substring('--output-file:'.length); | ||
} | ||
if (arg.startsWith('--project.')) { | ||
var name = arg.substring('--project.'.length, arg.indexOf('=')); | ||
var location = arg.substring(arg.indexOf('=') + 1); | ||
location = location.replace('{{_INTERNAL_URL_}}', '{{ INTERNAL_URL }}'); | ||
projects.push({ name: name, location: location }); | ||
} | ||
}); | ||
if (!editorPath && !editorEntry) { | ||
throw new Error('missing --editor-path: or --editor-entry: parameter'); | ||
if (!params.editorPath && !params.editorEntry && !params.editorContent) { | ||
throw new Error('missing editorPath or editorEntry or editorContent'); | ||
} | ||
if (editorEntry && !pluginRegistryUrl) { | ||
if (!params.devfilePath && !params.devfileUrl && !params.devfileContent) { | ||
throw new Error('missing devfilePath or devfileUrl or devfileContent'); | ||
} | ||
if (params.pluginRegistryUrl) { | ||
pluginRegistryUrl = params.pluginRegistryUrl; | ||
} | ||
else { | ||
pluginRegistryUrl = 'https://eclipse-che.github.io/che-plugin-registry/main/v3'; | ||
console.log("No plug-in registry url. Setting to " + pluginRegistryUrl); | ||
} | ||
if (!devfilePath && !devfileUrl) { | ||
throw new Error('missing --devfile-path: or --devfile-url: parameter'); | ||
} | ||
if (!outputFile) { | ||
throw new Error('missing --output-file: parameter'); | ||
} | ||
axiosInstance = axios["default"]; | ||
inversifyBinbding = new inversify_binding_1.InversifyBinding(); | ||
@@ -136,5 +112,5 @@ return [4 /*yield*/, inversifyBinbding.initBindings({ | ||
container.bind(generate_1.Generate).toSelf().inSingletonScope(); | ||
if (!devfileUrl) return [3 /*break*/, 3]; | ||
if (!params.devfileUrl) return [3 /*break*/, 3]; | ||
githubResolver = container.get(github_resolver_1.GithubResolver); | ||
githubUrl = githubResolver.resolve(devfileUrl); | ||
githubUrl = githubResolver.resolve(params.devfileUrl); | ||
return [4 /*yield*/, container.get(url_fetcher_1.UrlFetcher).fetchText(githubUrl.getContentUrl('devfile.yaml'))]; | ||
@@ -160,23 +136,32 @@ case 2: | ||
devfileContent = jsYaml.dump(devfileParsed); | ||
return [3 /*break*/, 5]; | ||
case 3: return [4 /*yield*/, fs.readFile(devfilePath)]; | ||
return [3 /*break*/, 6]; | ||
case 3: | ||
if (!params.devfilePath) return [3 /*break*/, 5]; | ||
return [4 /*yield*/, fs.readFile(params.devfilePath)]; | ||
case 4: | ||
devfileContent = _a.sent(); | ||
_a.label = 5; | ||
return [3 /*break*/, 6]; | ||
case 5: | ||
devfileContent = params.devfileContent; | ||
_a.label = 6; | ||
case 6: | ||
// enhance projects | ||
devfileContent = this.replaceIfExistingProjects(devfileContent, projects); | ||
if (!editorEntry) return [3 /*break*/, 7]; | ||
return [4 /*yield*/, container.get(plugin_registry_resolver_1.PluginRegistryResolver).loadDevfilePlugin(editorEntry)]; | ||
case 6: | ||
devfileContent = this.replaceIfExistingProjects(devfileContent, params.projects); | ||
if (!params.editorContent) return [3 /*break*/, 7]; | ||
editorContent = params.editorContent; | ||
return [3 /*break*/, 11]; | ||
case 7: | ||
if (!params.editorEntry) return [3 /*break*/, 9]; | ||
return [4 /*yield*/, container.get(plugin_registry_resolver_1.PluginRegistryResolver).loadDevfilePlugin(params.editorEntry)]; | ||
case 8: | ||
editorDevfile = _a.sent(); | ||
editorContent = jsYaml.dump(editorDevfile); | ||
return [3 /*break*/, 9]; | ||
case 7: return [4 /*yield*/, fs.readFile(editorPath)]; | ||
case 8: | ||
return [3 /*break*/, 11]; | ||
case 9: return [4 /*yield*/, fs.readFile(params.editorPath)]; | ||
case 10: | ||
editorContent = _a.sent(); | ||
_a.label = 9; | ||
case 9: | ||
_a.label = 11; | ||
case 11: | ||
generate = container.get(generate_1.Generate); | ||
return [2 /*return*/, generate.generate(devfileContent, editorContent, outputFile)]; | ||
return [2 /*return*/, generate.generate(devfileContent, editorContent, params.outputFile, params.injectDefaultComponent, params.defaultComponentImage)]; | ||
} | ||
@@ -214,12 +199,67 @@ }); | ||
return __awaiter(this, void 0, void 0, function () { | ||
var error_1; | ||
var devfilePath, devfileUrl, outputFile, editorPath, pluginRegistryUrl, editorEntry, injectDefaultComponent, defaultComponentImage, projects, args, error_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
_a.trys.push([0, 2, , 3]); | ||
return [4 /*yield*/, this.doStart()]; | ||
projects = []; | ||
args = process.argv.slice(2); | ||
args.forEach(function (arg) { | ||
if (arg.startsWith('--devfile-path:')) { | ||
devfilePath = arg.substring('--devfile-path:'.length); | ||
} | ||
if (arg.startsWith('--devfile-url:')) { | ||
devfileUrl = arg.substring('--devfile-url:'.length); | ||
} | ||
if (arg.startsWith('--plugin-registry-url:')) { | ||
pluginRegistryUrl = arg.substring('--plugin-registry-url:'.length); | ||
} | ||
if (arg.startsWith('--editor-entry:')) { | ||
editorEntry = arg.substring('--editor-entry:'.length); | ||
} | ||
if (arg.startsWith('--editor-path:')) { | ||
editorPath = arg.substring('--editor-path:'.length); | ||
} | ||
if (arg.startsWith('--output-file:')) { | ||
outputFile = arg.substring('--output-file:'.length); | ||
} | ||
if (arg.startsWith('--project.')) { | ||
var name = arg.substring('--project.'.length, arg.indexOf('=')); | ||
var location = arg.substring(arg.indexOf('=') + 1); | ||
location = location.replace('{{_INTERNAL_URL_}}', '{{ INTERNAL_URL }}'); | ||
projects.push({ name: name, location: location }); | ||
} | ||
if (arg.startsWith('--injectDefaultComponent:')) { | ||
injectDefaultComponent = arg.substring('--injectDefaultComponent:'.length); | ||
} | ||
if (arg.startsWith('--defaultComponentImage:')) { | ||
defaultComponentImage = arg.substring('--defaultComponentImage:'.length); | ||
} | ||
}); | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
if (!editorPath && !editorEntry) { | ||
throw new Error('missing --editor-path: or --editor-entry: parameter'); | ||
} | ||
if (!devfilePath && !devfileUrl) { | ||
throw new Error('missing --devfile-path: or --devfile-url: parameter'); | ||
} | ||
if (!outputFile) { | ||
throw new Error('missing --output-file: parameter'); | ||
} | ||
return [4 /*yield*/, this.generateDevfileContext({ | ||
devfilePath: devfilePath, | ||
devfileUrl: devfileUrl, | ||
editorPath: editorPath, | ||
outputFile: outputFile, | ||
pluginRegistryUrl: pluginRegistryUrl, | ||
editorEntry: editorEntry, | ||
projects: projects, | ||
injectDefaultComponent: injectDefaultComponent, | ||
defaultComponentImage: defaultComponentImage | ||
}, axios["default"])]; | ||
case 2: | ||
_a.sent(); | ||
return [2 /*return*/, true]; | ||
case 2: | ||
case 3: | ||
error_1 = _a.sent(); | ||
@@ -229,3 +269,3 @@ console.error('stack=' + error_1.stack); | ||
return [2 /*return*/, false]; | ||
case 3: return [2 /*return*/]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
@@ -232,0 +272,0 @@ }); |
@@ -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-d7aefd7", | ||
"version": "0.0.1-ea73e8b", | ||
"private": false, | ||
@@ -21,9 +21,11 @@ "description": "Generates DevWorkspaces by transforming existing devfiles", | ||
"build": "yarn run format && yarn run compile && yarn run lint && yarn run test", | ||
"compile": "tsc --project .", | ||
"compile": "tsc --declaration --project .", | ||
"format": "if-env SKIP_FORMAT=true && echo 'skip format check' || prettier --check '{src,tests}/**/*.ts' package.json", | ||
"format:fix": "prettier --write '{src,tests}/**/*.ts' package.json", | ||
"lint": "if-env SKIP_LINT=true && echo 'skip lint check' || eslint --cache=true --no-error-on-unmatched-pattern=true '{src,tests}/(!model|**)/*.ts'", | ||
"lint:fix": "eslint --fix --cache=true --no-error-on-unmatched-pattern=true \"{src,tests}/(!model|**)/*.{ts,tsx}\"", | ||
"lint:fix": "eslint --fix --cache=true --no-error-on-unmatched-pattern=true \"{src,tests}/(!model|**)/*.ts\"", | ||
"test": "if-env SKIP_TEST=true && echo 'skip test' || jest --forceExit", | ||
"watch": "tsc -w", | ||
"license:check": "docker run --rm -t -v ${PWD}/:/workspace/project quay.io/che-incubator/dash-licenses:next --check", | ||
"license:generate": "docker run --rm -t -v ${PWD}/:/workspace/project quay.io/che-incubator/dash-licenses:next", | ||
"publish:next": "yarn publish --registry=https://registry.npmjs.org/ --no-git-tag-version --new-version 0.0.1-\"$(date +%s)\"" | ||
@@ -76,3 +78,3 @@ }, | ||
"collectCoverageFrom": [ | ||
"src/**/*.{ts,tsx}" | ||
"src/**/*.ts" | ||
], | ||
@@ -79,0 +81,0 @@ "coverageThreshold": { |
@@ -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,20 +27,37 @@ 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 | ||
); | ||
// write the result | ||
// write templates and then DevWorkspace in a single file | ||
const allContentArray = context.devWorkspaceTemplates.map(template => jsYaml.dump(template)); | ||
allContentArray.push(jsYaml.dump(context.devWorkspace)); | ||
if (outputFile) { | ||
// write templates and then DevWorkspace in a single file | ||
const allContentArray = context.devWorkspaceTemplates.map(template => jsYaml.dump(template)); | ||
allContentArray.push(jsYaml.dump(context.devWorkspace)); | ||
const generatedContent = allContentArray.join('---\n'); | ||
const generatedContent = allContentArray.join('---\n'); | ||
await fs.writeFile(outputFile, generatedContent, 'utf-8'); | ||
await fs.writeFile(outputFile, generatedContent, 'utf-8'); | ||
} | ||
@@ -49,3 +68,8 @@ console.log(`DevWorkspace ${context.devWorkspaceTemplates[0].metadata.name} was generated.`); | ||
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); | ||
@@ -61,3 +85,3 @@ | ||
// transform it into a devWorkspace template | ||
const metadata = editorDevfile.metadata; | ||
const metadata = this.createDevWorkspaceMetadata(editorDevfile); | ||
// add sufix | ||
@@ -75,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); | ||
@@ -92,2 +116,3 @@ delete devfileCopy.schemaVersion; | ||
started: true, | ||
routingClass: 'che', | ||
template: devfileCopy, | ||
@@ -108,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; | ||
} | ||
} |
@@ -21,3 +21,3 @@ /********************************************************************** | ||
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>.*))?)?$/; | ||
@@ -29,2 +29,4 @@ resolve(link: string): GithubUrl { | ||
} | ||
const scheme = this.getGroup(match, 'scheme'); | ||
const hostName = this.getGroup(match, 'host'); | ||
const repoUser = this.getGroup(match, 'repoUser'); | ||
@@ -34,3 +36,3 @@ const repoName = this.getGroup(match, 'repoName'); | ||
const subFolder = this.getGroup(match, 'subFolder'); | ||
return new GithubUrl(repoUser, repoName, branchName, subFolder); | ||
return new GithubUrl(scheme, hostName, repoUser, repoName, branchName, subFolder); | ||
} | ||
@@ -37,0 +39,0 @@ |
@@ -15,6 +15,5 @@ /********************************************************************** | ||
export class GithubUrl { | ||
// raw link | ||
static readonly RAW_LINK = 'https://raw.githubusercontent.com'; | ||
constructor( | ||
private readonly scheme: string, | ||
private readonly hostName: string, | ||
private readonly repoUser: string, | ||
@@ -30,11 +29,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 +41,0 @@ |
174
src/main.ts
@@ -23,54 +23,41 @@ /********************************************************************** | ||
export class Main { | ||
protected async doStart(): Promise<DevfileContext> { | ||
let devfilePath: string | undefined; | ||
let devfileUrl: string | undefined; | ||
let outputFile: string | undefined; | ||
let editorPath: string | undefined; | ||
let pluginRegistryUrl: string | undefined; | ||
let editorEntry: string | undefined; | ||
const projects: { name: string; location: string }[] = []; | ||
/** | ||
* Default constructor. | ||
*/ | ||
constructor() { | ||
// no-op | ||
} | ||
// Generates a devfile context object based on params | ||
public async generateDevfileContext( | ||
params: { | ||
devfilePath?: string; | ||
devfileUrl?: string; | ||
devfileContent?: string; | ||
outputFile?: string; | ||
editorPath?: string; | ||
editorContent?: string; | ||
editorEntry?: string; | ||
pluginRegistryUrl?: string; | ||
projects: { name: string; location: string }[]; | ||
injectDefaultComponent?: string; | ||
defaultComponentImage?: string; | ||
}, | ||
axiosInstance: axios.AxiosInstance | ||
): Promise<DevfileContext> { | ||
if (!params.editorPath && !params.editorEntry && !params.editorContent) { | ||
throw new Error('missing editorPath or editorEntry or editorContent'); | ||
} | ||
if (!params.devfilePath && !params.devfileUrl && !params.devfileContent) { | ||
throw new Error('missing devfilePath or devfileUrl or devfileContent'); | ||
} | ||
const args = process.argv.slice(2); | ||
args.forEach(arg => { | ||
if (arg.startsWith('--devfile-path:')) { | ||
devfilePath = arg.substring('--devfile-path:'.length); | ||
} | ||
if (arg.startsWith('--devfile-url:')) { | ||
devfileUrl = arg.substring('--devfile-url:'.length); | ||
} | ||
if (arg.startsWith('--plugin-registry-url:')) { | ||
pluginRegistryUrl = arg.substring('--plugin-registry-url:'.length); | ||
} | ||
if (arg.startsWith('--editor-entry:')) { | ||
editorEntry = arg.substring('--editor-entry:'.length); | ||
} | ||
if (arg.startsWith('--editor-path:')) { | ||
editorPath = arg.substring('--editor-path:'.length); | ||
} | ||
if (arg.startsWith('--output-file:')) { | ||
outputFile = arg.substring('--output-file:'.length); | ||
} | ||
if (arg.startsWith('--project.')) { | ||
const name = arg.substring('--project.'.length, arg.indexOf('=')); | ||
let location = arg.substring(arg.indexOf('=') + 1); | ||
location = location.replace('{{_INTERNAL_URL_}}', '{{ INTERNAL_URL }}'); | ||
let pluginRegistryUrl: string; | ||
projects.push({ name, location }); | ||
} | ||
}); | ||
if (!editorPath && !editorEntry) { | ||
throw new Error('missing --editor-path: or --editor-entry: parameter'); | ||
} | ||
if (editorEntry && !pluginRegistryUrl) { | ||
if (params.pluginRegistryUrl) { | ||
pluginRegistryUrl = params.pluginRegistryUrl; | ||
} else { | ||
pluginRegistryUrl = 'https://eclipse-che.github.io/che-plugin-registry/main/v3'; | ||
console.log(`No plug-in registry url. Setting to ${pluginRegistryUrl}`); | ||
} | ||
if (!devfilePath && !devfileUrl) { | ||
throw new Error('missing --devfile-path: or --devfile-url: parameter'); | ||
} | ||
if (!outputFile) { | ||
throw new Error('missing --output-file: parameter'); | ||
} | ||
const axiosInstance = axios.default; | ||
const inversifyBinbding = new InversifyBinding(); | ||
@@ -87,5 +74,5 @@ const container = await inversifyBinbding.initBindings({ | ||
// gets the github URL | ||
if (devfileUrl) { | ||
if (params.devfileUrl) { | ||
const githubResolver = container.get(GithubResolver); | ||
const githubUrl = githubResolver.resolve(devfileUrl); | ||
const githubUrl = githubResolver.resolve(params.devfileUrl); | ||
// user devfile | ||
@@ -112,19 +99,29 @@ devfileContent = await container.get(UrlFetcher).fetchText(githubUrl.getContentUrl('devfile.yaml')); | ||
devfileContent = jsYaml.dump(devfileParsed); | ||
} else if (params.devfilePath) { | ||
devfileContent = await fs.readFile(params.devfilePath); | ||
} else { | ||
devfileContent = await fs.readFile(devfilePath); | ||
devfileContent = params.devfileContent; | ||
} | ||
// enhance projects | ||
devfileContent = this.replaceIfExistingProjects(devfileContent, projects); | ||
devfileContent = this.replaceIfExistingProjects(devfileContent, params.projects); | ||
if (editorEntry) { | ||
if (params.editorContent) { | ||
editorContent = params.editorContent; | ||
} else if (params.editorEntry) { | ||
// devfile of the editor | ||
const editorDevfile = await container.get(PluginRegistryResolver).loadDevfilePlugin(editorEntry); | ||
const editorDevfile = await container.get(PluginRegistryResolver).loadDevfilePlugin(params.editorEntry); | ||
editorContent = jsYaml.dump(editorDevfile); | ||
} else { | ||
editorContent = await fs.readFile(editorPath); | ||
editorContent = await fs.readFile(params.editorPath); | ||
} | ||
const generate = container.get(Generate); | ||
return generate.generate(devfileContent, editorContent, outputFile); | ||
return generate.generate( | ||
devfileContent, | ||
editorContent, | ||
params.outputFile, | ||
params.injectDefaultComponent, | ||
params.defaultComponentImage | ||
); | ||
} | ||
@@ -160,4 +157,71 @@ | ||
async start(): Promise<boolean> { | ||
let devfilePath: string | undefined; | ||
let devfileUrl: string | undefined; | ||
let outputFile: string | undefined; | ||
let editorPath: string | undefined; | ||
let pluginRegistryUrl: string | undefined; | ||
let editorEntry: string | undefined; | ||
let injectDefaultComponent: string | undefined; | ||
let defaultComponentImage: string | undefined; | ||
const projects: { name: string; location: string }[] = []; | ||
const args = process.argv.slice(2); | ||
args.forEach(arg => { | ||
if (arg.startsWith('--devfile-path:')) { | ||
devfilePath = arg.substring('--devfile-path:'.length); | ||
} | ||
if (arg.startsWith('--devfile-url:')) { | ||
devfileUrl = arg.substring('--devfile-url:'.length); | ||
} | ||
if (arg.startsWith('--plugin-registry-url:')) { | ||
pluginRegistryUrl = arg.substring('--plugin-registry-url:'.length); | ||
} | ||
if (arg.startsWith('--editor-entry:')) { | ||
editorEntry = arg.substring('--editor-entry:'.length); | ||
} | ||
if (arg.startsWith('--editor-path:')) { | ||
editorPath = arg.substring('--editor-path:'.length); | ||
} | ||
if (arg.startsWith('--output-file:')) { | ||
outputFile = arg.substring('--output-file:'.length); | ||
} | ||
if (arg.startsWith('--project.')) { | ||
const name = arg.substring('--project.'.length, arg.indexOf('=')); | ||
let location = arg.substring(arg.indexOf('=') + 1); | ||
location = location.replace('{{_INTERNAL_URL_}}', '{{ INTERNAL_URL }}'); | ||
projects.push({ name, location }); | ||
} | ||
if (arg.startsWith('--injectDefaultComponent:')) { | ||
injectDefaultComponent = arg.substring('--injectDefaultComponent:'.length); | ||
} | ||
if (arg.startsWith('--defaultComponentImage:')) { | ||
defaultComponentImage = arg.substring('--defaultComponentImage:'.length); | ||
} | ||
}); | ||
try { | ||
await this.doStart(); | ||
if (!editorPath && !editorEntry) { | ||
throw new Error('missing --editor-path: or --editor-entry: parameter'); | ||
} | ||
if (!devfilePath && !devfileUrl) { | ||
throw new Error('missing --devfile-path: or --devfile-url: parameter'); | ||
} | ||
if (!outputFile) { | ||
throw new Error('missing --output-file: parameter'); | ||
} | ||
await this.generateDevfileContext( | ||
{ | ||
devfilePath, | ||
devfileUrl, | ||
editorPath, | ||
outputFile, | ||
pluginRegistryUrl, | ||
editorEntry, | ||
projects, | ||
injectDefaultComponent, | ||
defaultComponentImage, | ||
}, | ||
axios.default | ||
); | ||
return true; | ||
@@ -164,0 +228,0 @@ } catch (error) { |
@@ -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
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 2 instances in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
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 3 instances in 1 package
129897
62
4
2213
1
57
165
9
26
1
113