From 04e273e0b12c3e33f19f5981bd3e5d1486275c4a Mon Sep 17 00:00:00 2001 From: Victor Rubezhny Date: Tue, 3 Oct 2023 00:11:09 +0200 Subject: [PATCH] Component create from Git fails if a devfile exists in git repo #3386 Fixes: #3386 Signed-off-by: Victor Rubezhny --- src/webview/common/devfile.ts | 6 +- src/webview/common/devfileListItem.tsx | 20 +++-- .../create-component/createComponentLoader.ts | 88 +++++++++++++++++-- .../pages/fromExistingGitRepo.tsx | 16 +++- 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/src/webview/common/devfile.ts b/src/webview/common/devfile.ts index d5a2c56fb..778c52801 100644 --- a/src/webview/common/devfile.ts +++ b/src/webview/common/devfile.ts @@ -8,10 +8,10 @@ import { StarterProject } from '../../odo/componentTypeDescription'; export type Devfile = { name: string; id: string; - port: number; - registryName: string; + port?: number; + registryName?: string; description: string; - logoUrl: string; + logoUrl?: string; supportsDebug: boolean; supportsDeploy: boolean; tags: string[]; diff --git a/src/webview/common/devfileListItem.tsx b/src/webview/common/devfileListItem.tsx index dab6ec9b8..95322f262 100644 --- a/src/webview/common/devfileListItem.tsx +++ b/src/webview/common/devfileListItem.tsx @@ -6,6 +6,7 @@ import { Check, Close } from '@mui/icons-material'; import { Box, Chip, Stack, Tooltip, Typography } from '@mui/material'; import * as React from 'react'; import { Devfile } from '../common/devfile'; +import DevfileLogo from '../../../images/context/devfile.png'; export type DevfileListItemProps = { devfile: Devfile; @@ -56,7 +57,7 @@ function DevfileListContent(props: DevfileListItemProps) { borderRadius: '4px', }} > - + {props.devfile.name} - - from {props.devfile.registryName} - + + {props.devfile.registryName && ( + + from {props.devfile.registryName} + + )} : } color={props.devfile.supportsDeploy ? 'success' : 'error'} /> - {props.devfile.tags.map((tag, i) => { + {(props.devfile.tags && props.devfile.tags.map((tag, i) => { if (i >= 4) { return; } return ; - })} - {props.devfile.tags.length > 4 && ( + }))} + {(props.devfile.tags && props.devfile.tags.length > 4 && ( - )} + ))} diff --git a/src/webview/create-component/createComponentLoader.ts b/src/webview/create-component/createComponentLoader.ts index 401633105..bca02e479 100644 --- a/src/webview/create-component/createComponentLoader.ts +++ b/src/webview/create-component/createComponentLoader.ts @@ -29,6 +29,7 @@ import { } from '../common-ext/createComponentHelpers'; import { loadWebviewHtml, validateGitURL } from '../common-ext/utils'; import { Devfile, DevfileRegistry, TemplateProjectIdentifier } from '../common/devfile'; +import { DevfileV1 } from '../../util/devfileV1Type'; interface CloneProcess { status: boolean; @@ -281,11 +282,19 @@ export default class CreateComponentLoader { action: 'cloneFailed', }); } else { + const isGirDevfileExists = await isDevfileExists(tmpFolder); void CreateComponentLoader.panel.webview.postMessage({ action: 'devfileExists', - data: await isDevfileExists(tmpFolder), + data: isGirDevfileExists, }); - void CreateComponentLoader.getRecommendedDevfile(tmpFolder); + + if (isGirDevfileExists) { + // Use the Devfile existing in Gir-repo + void CreateComponentLoader.getExistingDevfile(tmpFolder); + } else { + // Use recommended Devfile + void CreateComponentLoader.getRecommendedDevfile(tmpFolder); + } } break; } @@ -295,7 +304,7 @@ export default class CreateComponentLoader { case 'createComponent': { const componentName: string = message.data.componentName; const portNumber: number = message.data.portNumber; - let componentFolder: string; + let componentFolder: string = ''; try { if (message.data.isFromTemplateProject) { // from template project @@ -337,14 +346,19 @@ export default class CreateComponentLoader { await fse.copy(tmpFolder.fsPath, componentFolder); } const devfileType = getDevfileType(message.data.devfileDisplayName); - if (!await isDevfileExists(Uri.file(componentFolder))) { + const componentFolderUri = Uri.file(componentFolder); + if (!await isDevfileExists(componentFolderUri)) { await Odo.Instance.createComponentFromLocation( devfileType, componentName, portNumber, Uri.file(componentFolder), ); + } else { + // Update component devfile with component's selected name + await CreateComponentLoader.updateDevfileWithComponentName(componentFolderUri, componentName); } + await sendTelemetry('newComponentCreated', { strategy, // eslint-disable-next-line camelcase @@ -424,6 +438,66 @@ export default class CreateComponentLoader { } } + static async updateDevfileWithComponentName(ucomponentFolderUri: vscode.Uri, componentName: string): Promise { + const devFilePath = path.join(ucomponentFolderUri.fsPath, 'devfile.yaml'); + const file = await fs.readFile(devFilePath, 'utf8'); + const devfile = JSYAML.load(file.toString()) as any; + if (devfile?.metadata?.name !== componentName) { + devfile.metadata.name = componentName; + await fs.unlink(devFilePath); + const yaml = JSYAML.dump(devfile, { sortKeys: true }); + await fs.writeFile(devFilePath, yaml.toString(), 'utf-8'); + } + } + + static async getExistingDevfile(uri: Uri): Promise { + let rawDevfile: any; + let supportsDebug = false; // Initial value + let supportsDeploy = false; // Initial value + try { + void CreateComponentLoader.panel.webview.postMessage({ + action: 'getRecommendedDevfileStart' + }); + const componentDescription = await Odo.Instance.describeComponent(uri.fsPath); + if (componentDescription) { + rawDevfile = componentDescription.devfileData.devfile; + supportsDebug = componentDescription.devfileData.supportedOdoFeatures.debug; + supportsDeploy = componentDescription.devfileData.supportedOdoFeatures.deploy; + } + } catch (Error) { + // Will try reading the raw devfile + } finally { + if (!rawDevfile) { + //Try reading the raw devfile + const devFileYamlPath = path.join(tmpFolder.fsPath, 'devfile.yaml'); + const file = await fs.readFile(devFileYamlPath, 'utf8'); + rawDevfile = JSYAML.load(file.toString()); + } + + void CreateComponentLoader.panel.webview.postMessage({ + action: 'getRecommendedDevfile' + }); + + const devfile: Devfile = { + description: rawDevfile.metadata.description, + name: rawDevfile.metadata.displayName ? rawDevfile.metadata.displayName : rawDevfile.metadata.name, + id: rawDevfile.metadata.name, + starterProjects: rawDevfile.starterProjects, + tags: [], + yaml: JSYAML.dump(rawDevfile), + supportsDebug, + supportsDeploy, + } as Devfile; + + void CreateComponentLoader.panel.webview.postMessage({ + action: 'recommendedDevfile', + data: { + devfile, + }, + }); + } + } + static async getRecommendedDevfile(uri: Uri): Promise { let analyzeRes: AnalyzeResponse[] = []; let compDescriptions: ComponentTypeDescription[] = []; @@ -444,7 +518,7 @@ export default class CreateComponentLoader { try { const devFileV1Path = path.join(uri.fsPath, 'devfile.yaml'); const file = await fs.readFile(devFileV1Path, 'utf8'); - const devfileV1 = JSYAML.load(file.toString()); + const devfileV1 = JSYAML.load(file.toString()) as DevfileV1; await fs.unlink(devFileV1Path); analyzeRes = await Odo.Instance.analyze(uri.fsPath); compDescriptions = getCompDescription(analyzeRes); @@ -475,7 +549,7 @@ export default class CreateComponentLoader { }); const devfileRegistry: DevfileRegistry[] = getDevfileRegistries(); const allDevfiles: Devfile[] = devfileRegistry.flatMap((registry) => registry.devfiles); - const devfile: Devfile = + const devfile: Devfile | undefined = compDescriptions.length !== 0 ? allDevfiles.find( (devfile) => devfile.name === compDescriptions[0].displayName, @@ -515,7 +589,7 @@ function getDevfileType(devfileDisplayName: string): string { const devfileDescription: ComponentTypeDescription = Array.from(compDescriptions).find( (description) => description.displayName === devfileDisplayName, ); - return devfileDescription.name; + return devfileDescription ? devfileDescription.name : devfileDisplayName; } function getEndPoints(compDescription: ComponentTypeDescription): Endpoint[] { diff --git a/src/webview/create-component/pages/fromExistingGitRepo.tsx b/src/webview/create-component/pages/fromExistingGitRepo.tsx index 8d81808a4..3d804d50b 100644 --- a/src/webview/create-component/pages/fromExistingGitRepo.tsx +++ b/src/webview/create-component/pages/fromExistingGitRepo.tsx @@ -149,6 +149,18 @@ export function FromExistingGitRepo({ setCurrentView }) { setRecommendedDevfile((prevState) => ({ ...prevState, isLoading: true, completionValue: 5 })); } + function getEffectiveDevfile() { + return recommendedDevfile.isDevfileExistsInRepo ? + recommendedDevfile.devfile // An existing Git-Repo devfile + : selectedDevfile ? + selectedDevfile // A selected Devfile + : recommendedDevfile.devfile // A recommended Devfile + } + + function getInitialComponentName() { + return getEffectiveDevfile()?.name; + } + function createComponentFromGitRepo( projectFolder: string, componentName: string, @@ -454,8 +466,8 @@ export function FromExistingGitRepo({ setCurrentView }) { setCurrentPage('fromGitRepo'); }} createComponent={createComponentFromGitRepo} - devfile={recommendedDevfile.isDevfileExistsInRepo ? undefined : selectedDevfile ? selectedDevfile : recommendedDevfile.devfile} - initialComponentName={buildSanitizedComponentName(gitURL.url)} + devfile={getEffectiveDevfile()} + initialComponentName={buildSanitizedComponentName(getInitialComponentName())} /> ); case 'selectDifferentDevfile':