@eclipse-che/devfile-converter
Advanced tools
Comparing version
@@ -28,2 +28,6 @@ import { V220DevfileCommands, V220DevfileComponents, V220DevfileComponentsItemsContainerEndpoints, V220DevfileComponentsItemsContainerEnv, V220DevfileComponentsItemsContainerVolumeMounts, V220DevfileProjects, V220DevfileProjectsItemsGit } from '@devfile/api'; | ||
devfileV1toDevfileV2(devfileV1: che.workspace.devfile.Devfile): Promise<Devfile>; | ||
fixProjectsZipLocations(devfileV2: Devfile): Promise<void>; | ||
fixDuplicatedEndpoints(devfileV2: Devfile): Promise<void>; | ||
fixInvalidVolumeName(devfileV2: Devfile): Promise<void>; | ||
processVolumesFromDevfileV2(devfileV2: Devfile): Promise<void>; | ||
processPluginsAndEditorsFromDevfileV2(devfileV2: Devfile, devfileV1: che.workspace.devfile.Devfile, externalContentAccess?: (filename: string) => Promise<string>): Promise<void>; | ||
@@ -30,0 +34,0 @@ findFirstProjectPath(devfileV1: che.workspace.devfile.Devfile): string | undefined; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
@@ -83,2 +87,4 @@ if (k2 === undefined) k2 = k; | ||
volume.name = volumeV1.name; | ||
// volume names should not use _ | ||
volume.name = volume.name.replace(/_/g, '-'); | ||
} | ||
@@ -115,3 +121,12 @@ if (volumeV1.containerPath) { | ||
if (endpointV1.name) { | ||
endpoint.name = endpointV1.name; | ||
// the name can't have spaces | ||
// replace space by dash and then remove all special characters | ||
var endpointName = endpointV1.name | ||
.replace(/\s+/g, '-') | ||
// names should not use _ | ||
.replace(/_/g, '-') | ||
// trim '-' character from start or end | ||
.replace(/^\-+|\-+$/g, '') | ||
.toLowerCase(); | ||
endpoint.name = endpointName; | ||
} | ||
@@ -312,3 +327,13 @@ if (endpointV1.port) { | ||
// the id can't have spaces | ||
devfileV2Command.id = commandV1.name.replace(/\s+/g, '-').toLowerCase(); | ||
// replace space by dash and then remove all special characters | ||
devfileV2Command.id = commandV1.name | ||
.replace(/\s+/g, '-') | ||
.replace(/[^a-zA-Z-]/g, '') | ||
.toLowerCase(); | ||
// needs to be max 63 characters | ||
if (devfileV2Command.id.length > 63) { | ||
devfileV2Command.id = devfileV2Command.id.substring(0, 63); | ||
} | ||
// trim '-' character from start or end | ||
devfileV2Command.id = devfileV2Command.id.replace(/^\-+|\-+$/g, ''); | ||
} | ||
@@ -362,5 +387,16 @@ if (commandV1.actions && commandV1.actions[0].type === 'exec') { | ||
DevfileConverter.prototype.projectV1toProjectV2 = function (projectV1) { | ||
// the name can't have spaces | ||
// replace space by dash and then remove all special characters | ||
var projectName = projectV1.name | ||
.replace(/\s+/g, '-') | ||
// names should not use _ | ||
.replace(/_/g, '-') | ||
// names should not use . | ||
.replace(/\./g, '-') | ||
// trim '-' character from start or end | ||
.replace(/^\-+|\-+$/g, '') | ||
.toLowerCase(); | ||
var devfileV2Project = { | ||
attributes: {}, | ||
name: projectV1.name | ||
name: projectName | ||
}; | ||
@@ -372,3 +408,3 @@ if (projectV1.clonePath) { | ||
var source = projectV1.source; | ||
if (source.type === 'git' || source.type === 'github') { | ||
if (source.type === 'git' || source.type === 'github' || source.type === 'bitbucket') { | ||
var remotes = { origin: source.location }; | ||
@@ -446,2 +482,7 @@ devfileV2Project.git = { | ||
devfileMetadataV2.attributes['metadata-name-field'] = 'generateName'; | ||
devfileMetadataV2.attributes['metadata-name-original-value'] = metadataV1.generateName; | ||
// remove the trailing - to make it compliant with kubernetes name | ||
if (devfileMetadataV2.name.endsWith('-')) { | ||
devfileMetadataV2.name = devfileMetadataV2.name.slice(0, -1); | ||
} | ||
} | ||
@@ -464,4 +505,5 @@ if (metadataV1.name) { | ||
var nameField = metaDataAttributes['metadata-name-field']; | ||
if (nameField === 'generateName') { | ||
devfileMetadataV1.generateName = metadataV2.name; | ||
var originalValue = metaDataAttributes['metadata-name-original-value']; | ||
if (nameField === 'generateName' && originalValue) { | ||
devfileMetadataV1.generateName = originalValue; | ||
} | ||
@@ -476,2 +518,3 @@ else if (nameField === 'name') { | ||
delete metadataV2.attributes['metadata-name-field']; | ||
delete metadataV2.attributes['metadata-name-original-value']; | ||
} | ||
@@ -509,3 +552,5 @@ } | ||
} | ||
var cheTheiaPluginsContent = chePluginComponents.map(function (chePluginComponent) { | ||
var cheTheiaPluginsContent = chePluginComponents | ||
.filter(function (component) { return component.id; }) | ||
.map(function (chePluginComponent) { | ||
var cheTheiaPlugin = {}; | ||
@@ -515,5 +560,2 @@ if (chePluginComponent.id) { | ||
} | ||
if (chePluginComponent.reference) { | ||
cheTheiaPlugin.reference = chePluginComponent.reference; | ||
} | ||
cheTheiaPlugin.override = { | ||
@@ -567,5 +609,2 @@ sidecar: {} | ||
} | ||
if (cheEditorComponentV1.reference) { | ||
cheEditorYaml.reference = cheEditorComponentV1.reference; | ||
} | ||
if (cheEditorComponentV1.registryUrl) { | ||
@@ -610,39 +649,187 @@ cheEditorYaml.registryUrl = cheEditorComponentV1.registryUrl; | ||
return __generator(this, function (_b) { | ||
devfileV2 = { | ||
schemaVersion: '2.0.0', | ||
metadata: this.metadataV1toMetadataV2(devfileV1.metadata), | ||
projects: (devfileV1.projects || []).map(function (project) { return _this.projectV1toProjectV2(project); }), | ||
components: (devfileV1.components || []) | ||
.map(function (component) { return _this.componentV1toComponentV2(component); }) | ||
.filter(function (c) { return c; }), | ||
commands: (devfileV1.commands || []).map(function (command) { return _this.commandV1toCommandV2(command); }).filter(function (c) { return c; }) | ||
}; | ||
devfileV2.attributes = {}; | ||
inlineCheTheiaPluginsYaml = this.inlineCheTheiaPluginsYamlFromComponentsV1(devfileV1.components); | ||
if (inlineCheTheiaPluginsYaml) { | ||
devfileV2.attributes[this.CHE_THEIA_PLUGINS_YAML] = inlineCheTheiaPluginsYaml; | ||
switch (_b.label) { | ||
case 0: | ||
devfileV2 = { | ||
schemaVersion: '2.1.0', | ||
metadata: this.metadataV1toMetadataV2(devfileV1.metadata), | ||
projects: (devfileV1.projects || []).map(function (project) { return _this.projectV1toProjectV2(project); }), | ||
components: (devfileV1.components || []) | ||
.map(function (component) { return _this.componentV1toComponentV2(component); }) | ||
.filter(function (c) { return c; }), | ||
commands: (devfileV1.commands || []).map(function (command) { return _this.commandV1toCommandV2(command); }).filter(function (c) { return c; }) | ||
}; | ||
devfileV2.attributes = {}; | ||
// handle the ephemeral attribute | ||
if (devfileV1.attributes && | ||
devfileV1.attributes.persistVolumes && | ||
devfileV1.attributes.persistVolumes === 'false') { | ||
devfileV2.attributes['controller.devfile.io/storage-type'] = 'ephemeral'; | ||
} | ||
inlineCheTheiaPluginsYaml = this.inlineCheTheiaPluginsYamlFromComponentsV1(devfileV1.components); | ||
if (inlineCheTheiaPluginsYaml) { | ||
devfileV2.attributes[this.CHE_THEIA_PLUGINS_YAML] = inlineCheTheiaPluginsYaml; | ||
} | ||
inlineVsCodeExtensionJson = this.inlineVsCodeExtensionFromComponentsV1(devfileV1.components); | ||
if (inlineVsCodeExtensionJson) { | ||
devfileV2.attributes[this.VSCODE_EXTENSIONS_JSON] = inlineVsCodeExtensionJson; | ||
} | ||
inlineCheEditorYaml = this.inlineCheEditorYamlFromComponentsV1(devfileV1.components); | ||
if (inlineCheEditorYaml) { | ||
devfileV2.attributes[this.CHE_EDITOR_YAML] = inlineCheEditorYaml; | ||
} | ||
if (devfileV1.attributes) { | ||
Object.assign(devfileV2.metadata.attributes, {}); | ||
Object.keys(devfileV1.attributes).forEach(function (attributeName) { | ||
devfileV2.metadata.attributes[attributeName] = devfileV1.attributes[attributeName]; | ||
}); | ||
} | ||
launchCommand = (_a = devfileV1.commands) === null || _a === void 0 ? void 0 : _a.find(function (command) { return command.actions[0].type === 'vscode-launch'; }); | ||
if (launchCommand) { | ||
devfileV2.attributes[this.VSCODE_LAUNCH_JSON] = launchCommand.actions[0].referenceContent; | ||
} | ||
// fix duplicated endpoints (same properties (name, port, etc..) | ||
return [4 /*yield*/, this.fixDuplicatedEndpoints(devfileV2)]; | ||
case 1: | ||
// fix duplicated endpoints (same properties (name, port, etc..) | ||
_b.sent(); | ||
// process volumes | ||
return [4 /*yield*/, this.fixInvalidVolumeName(devfileV2)]; | ||
case 2: | ||
// process volumes | ||
_b.sent(); | ||
return [4 /*yield*/, this.processVolumesFromDevfileV2(devfileV2)]; | ||
case 3: | ||
_b.sent(); | ||
// fix zip project location (multi-host --> single-host) | ||
return [4 /*yield*/, this.fixProjectsZipLocations(devfileV2)]; | ||
case 4: | ||
// fix zip project location (multi-host --> single-host) | ||
_b.sent(); | ||
content = JSON.stringify(devfileV2); | ||
// update devfile v1 constants | ||
content = content.replace(/\$\(CHE_PROJECTS_ROOT\)/g, '$(PROJECTS_ROOT)'); | ||
content = content.replace(/\$\{CHE_PROJECTS_ROOT\}/g, '${PROJECTS_ROOT}'); | ||
return [2 /*return*/, JSON.parse(content)]; | ||
} | ||
inlineVsCodeExtensionJson = this.inlineVsCodeExtensionFromComponentsV1(devfileV1.components); | ||
if (inlineVsCodeExtensionJson) { | ||
devfileV2.attributes[this.VSCODE_EXTENSIONS_JSON] = inlineVsCodeExtensionJson; | ||
} | ||
inlineCheEditorYaml = this.inlineCheEditorYamlFromComponentsV1(devfileV1.components); | ||
if (inlineCheEditorYaml) { | ||
devfileV2.attributes[this.CHE_EDITOR_YAML] = inlineCheEditorYaml; | ||
} | ||
if (devfileV1.attributes) { | ||
Object.assign(devfileV2.metadata.attributes, {}); | ||
Object.keys(devfileV1.attributes).forEach(function (attributeName) { | ||
devfileV2.metadata.attributes[attributeName] = devfileV1.attributes[attributeName]; | ||
}); | ||
}); | ||
}; | ||
// if some endpoints have excactly the same value, remove duplicates | ||
DevfileConverter.prototype.fixProjectsZipLocations = function (devfileV2) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
// get projects | ||
devfileV2.projects.forEach(function (project) { | ||
if (project.zip && project.zip.location) { | ||
var location = project.zip.location; | ||
// if matching a pattern, then update the location | ||
var regex = /https:\/\/(devfile-registry|codeready|eclipse-che)-(?<namespace>.*?)\.(?<subdomain>.*)[\/.*]*\/resources\/(?<resourcelink>.*)/gm; | ||
var m = regex.exec(location); | ||
if (m !== null) { | ||
var namespace = m.groups.namespace; | ||
var resourcelink = m.groups.resourcelink; | ||
var newLocation = "http://devfile-registry.".concat(namespace, ".svc:8080/resources/").concat(resourcelink); | ||
project.zip.location = newLocation; | ||
} | ||
} | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
}; | ||
// if some endpoints have excactly the same value, remove duplicates | ||
DevfileConverter.prototype.fixDuplicatedEndpoints = function (devfileV2) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var endpoints, uniqueEndpoints, uniqueEndpointsJson, alreadyProcessedEndpoints; | ||
return __generator(this, function (_a) { | ||
endpoints = devfileV2.components | ||
.filter(function (component) { return component.container; }) | ||
.map(function (component) { return component.container.endpoints; }) | ||
.flat(); | ||
uniqueEndpoints = endpoints.filter(function (value, index) { | ||
var _value = JSON.stringify(value); | ||
return (index === | ||
endpoints.findIndex(function (obj) { | ||
return JSON.stringify(obj) === _value; | ||
})); | ||
}); | ||
uniqueEndpointsJson = uniqueEndpoints.map(function (endpoint) { return JSON.stringify(endpoint); }); | ||
alreadyProcessedEndpoints = []; | ||
// ok now we'll iterate on endpoints and check if we need to replace endpoint if it's already been added | ||
devfileV2.components | ||
.filter(function (component) { return component.container; }) | ||
.forEach(function (component) { | ||
var endpoints = component.container.endpoints || []; | ||
var i = endpoints.length; | ||
while (i--) { | ||
var jsonEndpoint = JSON.stringify(endpoints[i]); | ||
if (uniqueEndpointsJson.includes(jsonEndpoint)) { | ||
// first time we see, we keep | ||
if (!alreadyProcessedEndpoints.includes(jsonEndpoint)) { | ||
alreadyProcessedEndpoints.push(jsonEndpoint); | ||
} | ||
else { | ||
// need to remove this endpoint | ||
endpoints.splice(i, 1); | ||
} | ||
} | ||
} | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
}; | ||
// if some volume component are also components, update the name of the volume component | ||
// to be componentName-volume | ||
DevfileConverter.prototype.fixInvalidVolumeName = function (devfileV2) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var mountedVolumes, mountedVolumeNames, allComponentExceptVolumeNames, invalidVolumeNames; | ||
return __generator(this, function (_a) { | ||
mountedVolumes = devfileV2.components | ||
.map(function (component) { return component.container; }) | ||
.filter(function (container) { return container; }) | ||
.map(function (container) { return container.volumeMounts; }) | ||
.reduce(function (acc, volumeMounts) { return acc.concat(volumeMounts); }, []) | ||
.filter(function (volume) { return volume; }); | ||
mountedVolumeNames = mountedVolumes.map(function (volume) { return volume.name; }); | ||
allComponentExceptVolumeNames = devfileV2.components | ||
.filter(function (component) { return !component.volume; }) | ||
.map(function (component) { return component.name; }); | ||
invalidVolumeNames = mountedVolumeNames.filter(function (componentName) { | ||
return allComponentExceptVolumeNames.includes(componentName); | ||
}); | ||
// we have duplicates, need to update the volume name | ||
mountedVolumes.forEach(function (volume) { | ||
if (invalidVolumeNames.includes(volume.name)) { | ||
volume.name = "".concat(volume.name, "-volume"); | ||
} | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
}; | ||
// add missing volumes components when a volumeMount is defined in the devfile | ||
DevfileConverter.prototype.processVolumesFromDevfileV2 = function (devfileV2) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var mountedVolumes, mountedVolumeNames, allComponentVolumeNames, missingVolumes; | ||
return __generator(this, function (_a) { | ||
mountedVolumes = devfileV2.components | ||
.map(function (component) { return component.container; }) | ||
.filter(function (container) { return container; }) | ||
.map(function (container) { return container.volumeMounts; }) | ||
.reduce(function (acc, volumeMounts) { return acc.concat(volumeMounts); }, []) | ||
.filter(function (volume) { return volume; }); | ||
mountedVolumeNames = mountedVolumes.map(function (volume) { return volume.name; }); | ||
allComponentVolumeNames = devfileV2.components | ||
.filter(function (component) { return component.volume; }) | ||
.map(function (component) { return component.name; }); | ||
missingVolumes = Array.from(new Set(mountedVolumeNames.filter(function (volumeName) { return !allComponentVolumeNames.includes(volumeName); }))); | ||
// add missing volumes | ||
missingVolumes.forEach(function (volumeName) { | ||
devfileV2.components.push({ | ||
name: volumeName, | ||
volume: {} | ||
}); | ||
} | ||
launchCommand = (_a = devfileV1.commands) === null || _a === void 0 ? void 0 : _a.find(function (command) { return command.actions[0].type === 'vscode-launch'; }); | ||
if (launchCommand) { | ||
devfileV2.attributes[this.VSCODE_LAUNCH_JSON] = launchCommand.actions[0].referenceContent; | ||
} | ||
content = JSON.stringify(devfileV2); | ||
// update devfile v1 constants | ||
content = content.replace(/\$\(CHE_PROJECTS_ROOT\)/g, '$(PROJECTS_ROOT)'); | ||
content = content.replace(/\$\{CHE_PROJECTS_ROOT\}/g, '${PROJECTS_ROOT}'); | ||
return [2 /*return*/, JSON.parse(content)]; | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
@@ -742,5 +929,2 @@ }); | ||
} | ||
if (component.reference) { | ||
v1component.reference = component.reference; | ||
} | ||
if (component.registryUrl) { | ||
@@ -797,5 +981,2 @@ v1component.registryUrl = component.registryUrl; | ||
} | ||
if (cheEditorYaml.reference) { | ||
v1component.reference = cheEditorYaml.reference; | ||
} | ||
if (cheEditorYaml.registryUrl) { | ||
@@ -802,0 +983,0 @@ v1component.registryUrl = cheEditorYaml.registryUrl; |
{ | ||
"name": "@eclipse-che/devfile-converter", | ||
"version": "0.0.1-eb20432", | ||
"version": "0.0.1-eca41d9", | ||
"description": "Convert devfile v1 to v2 or v2 to v1", | ||
@@ -73,2 +73,10 @@ "publishConfig": { | ||
], | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 100, | ||
"functions": 100, | ||
"lines": 100, | ||
"statements": 100 | ||
} | ||
}, | ||
"coverageDirectory": "coverage", | ||
@@ -75,0 +83,0 @@ "modulePathIgnorePatterns": [ |
@@ -18,1 +18,5 @@ # devfile-converter | ||
``` | ||
# Trademark | ||
"Che" is a trademark of the Eclipse Foundation. |
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
129854
14.53%1486
14.22%22
22.22%