diff --git a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/__tests__/prepareDevfile.spec.ts b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/__tests__/prepareDevfile.spec.ts index 3d82fe0e5..1abb49956 100644 --- a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/__tests__/prepareDevfile.spec.ts +++ b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/__tests__/prepareDevfile.spec.ts @@ -27,6 +27,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { describe('DEVWORKSPACE_METADATA_ANNOTATION attribute', () => { test('add the attribute with annotation', () => { const devfile = { + schemaVersion: '2.1.0', metadata: { generateName: 'wksp-', }, @@ -42,7 +43,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { const newDevfile = prepareDevfile(devfile, factoryId, undefined, false); - expect(newDevfile.metadata.attributes).toEqual({ + expect(newDevfile.attributes).toEqual({ [DEVWORKSPACE_METADATA_ANNOTATION]: factorySource, }); }); @@ -65,18 +66,18 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { metadata: { name: 'asdf', generateName: 'wksp-', - attributes: { - [DEVWORKSPACE_METADATA_ANNOTATION]: customAnnotation, - }, + }, + attributes: { + [DEVWORKSPACE_METADATA_ANNOTATION]: customAnnotation, }, } as devfileApi.Devfile; const newDevfile = prepareDevfile(devfile, factoryId, undefined, false); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( expect.objectContaining(customAnnotation), ); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( expect.objectContaining(factorySource), ); }); @@ -94,6 +95,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { const badMetadataAnnotation = 'bad-metadata-annotation'; const devfile = { + schemaVersion: '2.1.0', metadata: { generateName: 'wksp-', attributes: { @@ -104,12 +106,10 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { const newDevfile = prepareDevfile(devfile, factoryId, undefined, false); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).not.toContain( + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).not.toContain( badMetadataAnnotation, ); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( - factorySource, - ); + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual(factorySource); }); test('update the attribute with annotation - bad DEVWORKSPACE_DEVFILE_SOURCE', () => { @@ -127,6 +127,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { }; const devfile = { + schemaVersion: '2.1.0', metadata: { generateName: 'wksp-', attributes: { @@ -137,12 +138,10 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { const newDevfile = prepareDevfile(devfile, factoryId, undefined, false); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).not.toContain( + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).not.toContain( expect.objectContaining(badDevworkspaceDevfileSource), ); - expect(newDevfile.metadata.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual( - factorySource, - ); + expect(newDevfile.attributes?.[DEVWORKSPACE_METADATA_ANNOTATION]).toEqual(factorySource); }); }); @@ -150,6 +149,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { it('should not change the name', () => { const factoryId = 'url=https://devfile-location'; const devfile = { + schemaVersion: '2.1.0', metadata: { name: 'wksp-test', }, @@ -163,6 +163,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { it('should append a suffix to the name', () => { const factoryId = 'url=https://devfile-location'; const devfile = { + schemaVersion: '2.1.0', metadata: { name: 'wksp-test', }, @@ -176,6 +177,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { it('should generate a new name #1', () => { const factoryId = 'url=https://devfile-location'; const devfile = { + schemaVersion: '2.1.0', metadata: { generateName: 'wksp-', }, @@ -189,6 +191,7 @@ describe('FactoryLoaderContainer/prepareDevfile', () => { it('should generate a new name #2', () => { const factoryId = 'url=https://devfile-location'; const devfile = { + schemaVersion: '2.1.0', metadata: { generateName: 'wksp-', }, diff --git a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/prepareDevfile.ts b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/prepareDevfile.ts index 984d4b4e9..68669b034 100644 --- a/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/prepareDevfile.ts +++ b/packages/dashboard-frontend/src/containers/Loader/Factory/Steps/Apply/Devfile/prepareDevfile.ts @@ -20,6 +20,7 @@ import { DEVWORKSPACE_DEVFILE_SOURCE, DEVWORKSPACE_METADATA_ANNOTATION, } from '../../../../../../services/workspace-client/devworkspace/devWorkspaceClient'; +import { DevfileAdapter } from '../../../../../../services/devfile/adapter'; export type FactorySource = { factory?: { params: string } }; @@ -30,26 +31,21 @@ export function prepareDevfile( appendSuffix: boolean, ): devfileApi.Devfile { const devfile = cloneDeep(_devfile); - - // set factory ID - if (!devfile.metadata.attributes) { - devfile.metadata.attributes = {}; - } + const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfile); if ( - !devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] || - typeof devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] !== 'object' + !attributes[DEVWORKSPACE_METADATA_ANNOTATION] || + typeof attributes[DEVWORKSPACE_METADATA_ANNOTATION] !== 'object' ) { - devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; + attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; } - const dwMetadataAnnotations = devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION]; + const dwMetadataAnnotations = attributes[DEVWORKSPACE_METADATA_ANNOTATION]; const devfileSourceYaml = dwMetadataAnnotations[DEVWORKSPACE_DEVFILE_SOURCE]; let devfileSource = devfileSourceYaml ? load(devfileSourceYaml) : {}; if (typeof devfileSource !== 'object') { devfileSource = {}; } (devfileSource as FactorySource).factory = { params: factoryId }; - devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = - dump(devfileSource); + attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = dump(devfileSource); // update `metadata.name` in accordance to the policy if (devfile.metadata.generateName) { @@ -63,15 +59,7 @@ export function prepareDevfile( // propagate storage type if (storageType === 'ephemeral') { - if (devfile.schemaVersion === '2.0.0') { - devfile.metadata.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = 'ephemeral'; - } else { - // for devfiles version 2.1.0 and above - if (!devfile.attributes) { - devfile.attributes = {}; - } - devfile.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = 'ephemeral'; - } + attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = 'ephemeral'; } return devfile; diff --git a/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts b/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts index d64291ac4..e1a403df8 100644 --- a/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts +++ b/packages/dashboard-frontend/src/services/devfile/__tests__/devfileAdapter.spec.ts @@ -14,8 +14,49 @@ import { DevfileBuilder } from '../../../store/__mocks__/devfile'; import { DEVWORKSPACE_STORAGE_TYPE_ATTR } from '../../devfileApi/devWorkspace/spec/template'; import { DevfileAdapter } from '../adapter'; import { convertDevfileV1toDevfileV2 } from '../converters'; +import devfileApi from '../../devfileApi'; describe('DevfileAdapter Service', () => { + describe('getAttributesFromDevfileV2', () => { + it('should returns attributes from the devfile v2.0.0', async () => { + const devfileV2 = { + schemaVersion: '2.0.0', + metadata: { + name: 'wksp-test', + }, + } as devfileApi.Devfile; + const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); + + expect(attributes === devfileV2.metadata.attributes).toBeTruthy(); + expect(attributes === devfileV2.attributes).toBeFalsy(); + }); + + it('should returns attributes from the devfile v2.1.0', async () => { + const devfileV2 = { + schemaVersion: '2.1.0', + metadata: { + name: 'wksp-test', + }, + } as devfileApi.Devfile; + const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); + + expect(attributes === devfileV2.metadata.attributes).toBeFalsy(); + expect(attributes === devfileV2.attributes).toBeTruthy(); + }); + + it('should returns attributes from the devfile v2.2.0', async () => { + const devfileV2 = { + schemaVersion: '2.2.0', + metadata: { + name: 'wksp-test', + }, + } as devfileApi.Devfile; + const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfileV2); + + expect(attributes === devfileV2.metadata.attributes).toBeFalsy(); + expect(attributes === devfileV2.attributes).toBeTruthy(); + }); + }); describe('update storageType', () => { describe('devfile V2', () => { describe('setting the "ephemeral" storage', () => { diff --git a/packages/dashboard-frontend/src/services/devfile/adapter.ts b/packages/dashboard-frontend/src/services/devfile/adapter.ts index da5c85fae..728aa3973 100644 --- a/packages/dashboard-frontend/src/services/devfile/adapter.ts +++ b/packages/dashboard-frontend/src/services/devfile/adapter.ts @@ -23,36 +23,43 @@ export class DevfileAdapter { this._devfile = devfile; } + public static getAttributesFromDevfileV2(devfile: devfileApi.Devfile) { + let attributes = {}; + if (devfile.schemaVersion?.startsWith('2.0')) { + if (!devfile.metadata.attributes) { + devfile.metadata.attributes = attributes; + } else { + attributes = devfile.metadata.attributes; + } + } else { + if (!devfile.attributes) { + devfile.attributes = attributes; + } else { + attributes = devfile.attributes; + } + } + + return attributes; + } + get devfile(): Devfile { return this._devfile; } set storageType(type: che.WorkspaceStorageType) { if (isDevfileV2(this._devfile)) { + const attributes = DevfileAdapter.getAttributesFromDevfileV2(this._devfile); if (type && type !== 'persistent') { - if (this._devfile.schemaVersion === '2.0.0') { - if (!this._devfile.metadata.attributes) { - this._devfile.metadata.attributes = {}; - } - this._devfile.metadata.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; - } else { - // for devfiles version 2.1.0 and above - if (!this._devfile.attributes) { - this._devfile.attributes = {}; - } - this._devfile.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; - } + attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR] = type; } else { - if (this._devfile.metadata.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { - delete this._devfile.metadata.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - if (Object.keys(this._devfile.metadata.attributes).length === 0) { - delete this._devfile.metadata.attributes; - } + if (attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { + delete attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; } - if (this._devfile.attributes?.[DEVWORKSPACE_STORAGE_TYPE_ATTR]) { - delete this._devfile.attributes[DEVWORKSPACE_STORAGE_TYPE_ATTR]; - if (Object.keys(this._devfile.attributes).length === 0) { + if (Object.keys(attributes).length === 0) { + if (this._devfile.attributes === attributes) { delete this._devfile.attributes; + } else if (this._devfile.metadata.attributes === attributes) { + delete this._devfile.metadata.attributes; } } } diff --git a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts b/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts index 9171afd46..fc5e24f1a 100644 --- a/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts +++ b/packages/dashboard-frontend/src/store/FactoryResolver/normalizeDevfileV2.ts @@ -22,6 +22,7 @@ import { } from '../../services/workspace-client/devworkspace/devWorkspaceClient'; import { generateWorkspaceName } from '../../services/helpers/generateName'; import { FactoryParams } from '../../containers/Loader/buildFactoryParams'; +import { DevfileAdapter } from '../../services/devfile/adapter'; /** * Returns a devfile from the FactoryResolver object. @@ -110,14 +111,13 @@ export default function normalizeDevfileV2( } else if (location) { devfileSource = dump({ url: { location } }); } - if (!devfile.metadata.attributes) { - devfile.metadata.attributes = {}; - } - if (!devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION]) { - devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; + + const attributes = DevfileAdapter.getAttributesFromDevfileV2(devfile); + + if (!attributes[DEVWORKSPACE_METADATA_ANNOTATION]) { + attributes[DEVWORKSPACE_METADATA_ANNOTATION] = {}; } - devfile.metadata.attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = - devfileSource; + attributes[DEVWORKSPACE_METADATA_ANNOTATION][DEVWORKSPACE_DEVFILE_SOURCE] = devfileSource; return devfile; }