Skip to content

Commit 44ebc51

Browse files
Replace odo analyze command (#4330)
* chaged the image path and removed (formerly Red Hat CodeReady Containers) text Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * removed odo analyze command Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * addressed review comments Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * added alizer test Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed no-unused-vars error Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed test case fails Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * added deleteComponentConfiguration Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * fixed mapping component description Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * addressed review comments Signed-off-by: msivasubramaniaan <msivasub@redhat.com> * addressed review comments Signed-off-by: msivasubramaniaan <msivasub@redhat.com> --------- Signed-off-by: msivasubramaniaan <msivasub@redhat.com>
1 parent 4ff8310 commit 44ebc51

File tree

9 files changed

+256
-44
lines changed

9 files changed

+256
-44
lines changed

src/alizer/alizerWrapper.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
6+
import { CommandText } from '../base/command';
7+
import { CliChannel } from '../cli';
8+
import { Uri } from 'vscode';
9+
import { CliExitData } from '../util/childProcessUtil';
10+
import { AlizerAnalyzeResponse } from './types';
11+
12+
/**
13+
* A wrapper around the `alizer` CLI tool.
14+
*
15+
* This class is a stateless singleton.
16+
* This makes it easier to stub its methods than if it were a bunch of directly exported functions.
17+
*/
18+
export class Alizer {
19+
private static INSTANCE = new Alizer();
20+
21+
static get Instance() {
22+
return Alizer.INSTANCE;
23+
}
24+
25+
public async alizerAnalyze(currentFolderPath: Uri): Promise<AlizerAnalyzeResponse> {
26+
const cliData: CliExitData = await CliChannel.getInstance().executeTool(
27+
new CommandText('alizer', `devfile ${currentFolderPath.fsPath}`), undefined, false
28+
);
29+
if (cliData.error || cliData.stderr.length > 0) {
30+
return undefined;
31+
}
32+
const parse = JSON.parse(cliData.stdout) as AlizerAnalyzeResponse[];
33+
return parse[0];
34+
}
35+
}

src/alizer/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
6+
export interface Version {
7+
SchemaVersion: number;
8+
Default: boolean;
9+
Version: string;
10+
}
11+
12+
export interface AlizerAnalyzeResponse {
13+
Name: string;
14+
Language: string;
15+
ProjectType: string;
16+
Tags: string[];
17+
Versions: Version[];
18+
}

src/downloadUtil/downloadBinaries.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ export async function downloadFileAndCreateSha256(
5757
console.log(`${current}%`),
5858
);
5959
const currentSHA256 = await hasha.fromFile(currentFile, { algorithm: 'sha256' });
60-
if (currentSHA256 === platform.sha256sum) {
61-
console.log(`Download of ${currentFile} has finished and SHA256 is correct`);
62-
} else {
63-
throw Error(`${currentFile} is downloaded and SHA256 is not correct`);
60+
if (platform.sha256sum) {
61+
if (currentSHA256 === platform.sha256sum) {
62+
console.log(`Download of ${currentFile} has finished and SHA256 is correct`);
63+
} else {
64+
throw Error(`${currentFile} is downloaded and SHA256 is not correct`);
65+
}
6466
}
6567
if (process.env.REMOTE_CONTAINERS === 'true') {
6668
await extractTool(toolsFolder, platform, currentFile);

src/odo/odoWrapper.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { ToolsConfig } from '../tools';
1111
import { ChildProcessUtil, CliExitData } from '../util/childProcessUtil';
1212
import { VsCommandError } from '../vscommand';
1313
import { Command } from './command';
14-
import { AnalyzeResponse, ComponentTypeAdapter, ComponentTypeDescription, DevfileComponentType, Registry } from './componentType';
14+
import { ComponentTypeAdapter, ComponentTypeDescription, DevfileComponentType, Registry } from './componentType';
1515
import { ComponentDescription, StarterProject } from './componentTypeDescription';
1616
import { BindableService } from './odoTypes';
1717

@@ -194,15 +194,6 @@ export class Odo {
194194
);
195195
}
196196

197-
public async analyze(currentFolderPath: string): Promise<AnalyzeResponse[]> {
198-
const cliData: CliExitData = await this.execute(
199-
new CommandText('odo', 'analyze -o json'),
200-
currentFolderPath,
201-
);
202-
const parse = JSON.parse(cliData.stdout) as AnalyzeResponse[];
203-
return parse;
204-
}
205-
206197
/**
207198
* Returns a list of starter projects for the given Devfile
208199
*

src/tools.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,43 @@
173173
}
174174
}
175175
},
176+
"alizer": {
177+
"description": "Alizer CLI tool",
178+
"vendor": "The Devfile Project",
179+
"name": "alizer",
180+
"version": "1.6.0",
181+
"versionRange": "^1.6.0",
182+
"versionRangeLabel": "version >= 1.6.0",
183+
"dlFileName": "alizer",
184+
"filePrefix": "",
185+
"platform": {
186+
"win32": {
187+
"url": "https://github.com/devfile/alizer/releases/download/v1.6.0/alizer-v1.6.0-windows-amd64.exe",
188+
"dlFileName": "alizer_windows_amd64.exe",
189+
"cmdFileName": "alizer.exe"
190+
},
191+
"darwin": {
192+
"url": "https://github.com/devfile/alizer/releases/download/v1.6.0/alizer-v1.6.0-darwin-amd64",
193+
"dlFileName": "alizer_darwin_amd64",
194+
"cmdFileName": "alizer"
195+
},
196+
"darwin-arm64": {
197+
"url": "https://github.com/devfile/alizer/releases/download/v1.6.0/alizer-v1.6.0-darwin-arm64",
198+
"dlFileName": "alizer_darwin_arm64",
199+
"cmdFileName": "alizer"
200+
},
201+
"linux": {
202+
"url": "https://github.com/devfile/alizer/releases/download/v1.6.0/alizer-v1.6.0-linux-amd64",
203+
"dlFileName": "alizer_linux_amd64",
204+
"cmdFileName": "alizer"
205+
},
206+
"linux-arm64": {
207+
"url": "https://github.com/devfile/alizer/releases/download/v1.6.0/alizer-v1.6.0-linux-arm64",
208+
"dlFileName": "alizer_linux_arm64",
209+
"cmdFileName": "alizer"
210+
}
211+
}
212+
},
176213
"crc": {
177214
"description": "crc openshift container",
178215
"vendor": "Red Hat, Inc.",

src/tools.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,12 @@ export class ToolsConfig {
9292
public static async selectTool(locations: string[], versionRange: string): Promise<string> {
9393
let result: string;
9494
const funcValue = Platform.OS !== 'win32' ? 'func' : 'func.exe';
95+
const alizerValue = Platform.OS !== 'win32' ? 'alizer' : 'alizer.exe';
9596
// Array.find cannot be used here because of async calls
9697
for (const location of locations) {
9798
// FIXME: see https://github.com/knative/func/issues/2067
9899
// eslint-disable-next-line no-await-in-loop
99-
if (location && (location.endsWith(funcValue) || semver.satisfies(await ToolsConfig.getVersion(location), versionRange))) {
100+
if (location && (location.endsWith(funcValue) || location.endsWith(alizerValue) || semver.satisfies(await ToolsConfig.getVersion(location), versionRange))) {
100101
result = location;
101102
break;
102103
}

src/webview/create-component/createComponentLoader.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as tmp from 'tmp';
1111
import { promisify } from 'util';
1212
import * as vscode from 'vscode';
1313
import { extensions, Uri, ViewColumn, WebviewPanel, window } from 'vscode';
14-
import { AnalyzeResponse, ComponentTypeDescription } from '../../odo/componentType';
14+
import { ComponentTypeDescription } from '../../odo/componentType';
1515
import { Endpoint } from '../../odo/componentTypeDescription';
1616
import { Odo } from '../../odo/odoWrapper';
1717
import { ComponentTypesView } from '../../registriesView';
@@ -30,6 +30,8 @@ import {
3030
} from '../common-ext/createComponentHelpers';
3131
import { loadWebviewHtml, validateGitURL } from '../common-ext/utils';
3232
import { Devfile, DevfileRegistry, TemplateProjectIdentifier } from '../common/devfile';
33+
import { AlizerAnalyzeResponse, Version } from '../../alizer/types';
34+
import { Alizer } from '../../alizer/alizerWrapper';
3335

3436
interface CloneProcess {
3537
status: boolean;
@@ -518,14 +520,14 @@ export default class CreateComponentLoader {
518520
}
519521

520522
static async getRecommendedDevfile(uri: Uri): Promise<void> {
521-
let analyzeRes: AnalyzeResponse[] = [];
523+
let analyzeRes: AlizerAnalyzeResponse;
522524
let compDescriptions: ComponentTypeDescription[] = [];
523525
try {
524526
void CreateComponentLoader.panel.webview.postMessage({
525527
action: 'getRecommendedDevfileStart'
526528
});
527-
analyzeRes = await Odo.Instance.analyze(uri.fsPath);
528-
compDescriptions = await getCompDescription(analyzeRes);
529+
const alizerAnalyzeRes: AlizerAnalyzeResponse = await Alizer.Instance.alizerAnalyze(uri);
530+
compDescriptions = await getCompDescription(alizerAnalyzeRes);
529531
} catch (error) {
530532
if (error.message.toLowerCase().indexOf('failed to parse the devfile') !== -1) {
531533
const actions: Array<string> = ['Yes', 'Cancel'];
@@ -539,7 +541,7 @@ export default class CreateComponentLoader {
539541
const file = await fs.readFile(devFileV1Path, 'utf8');
540542
const devfileV1 = JSYAML.load(file.toString()) as DevfileV1;
541543
await fs.unlink(devFileV1Path);
542-
analyzeRes = await Odo.Instance.analyze(uri.fsPath);
544+
analyzeRes = await Alizer.Instance.alizerAnalyze(uri);
543545
compDescriptions = await getCompDescription(analyzeRes);
544546
const endPoints = getEndPoints(compDescriptions[0]);
545547
const devfileV2 = DevfileConverter.getInstance().devfileV1toDevfileV2(
@@ -587,18 +589,25 @@ export default class CreateComponentLoader {
587589
}
588590
}
589591

590-
async function getCompDescription(devfiles: AnalyzeResponse[]): Promise<ComponentTypeDescription[]> {
592+
async function getCompDescription(devfile: AlizerAnalyzeResponse): Promise<ComponentTypeDescription[]> {
591593
const compDescriptions = await ComponentTypesView.instance.getCompDescriptions();
592-
if (devfiles.length === 0) {
594+
if (!devfile) {
593595
return Array.from(compDescriptions);
594596
}
595-
return Array.from(compDescriptions).filter(({ name, version, registry }) =>
596-
devfiles.some(
597-
(res) =>
598-
res.devfile === name &&
599-
res.devfileVersion === version &&
600-
res.devfileRegistry === registry.name,
601-
),
597+
return Array.from(compDescriptions).filter((compDesc) => {
598+
if (devfile.Name === compDesc.name && getVersion(devfile.Versions, compDesc.version)) {
599+
return compDesc;
600+
}
601+
}
602+
);
603+
}
604+
605+
function getVersion(devfileVersions: Version[], matchedVersion: string): Version {
606+
return devfileVersions.find((devfileVersion) => {
607+
if (devfileVersion.Version === matchedVersion) {
608+
return devfileVersion;
609+
}
610+
}
602611
);
603612
}
604613

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
import { fail } from 'assert';
6+
import { expect } from 'chai';
7+
import * as fs from 'fs/promises';
8+
import { suite, suiteSetup } from 'mocha';
9+
import * as tmp from 'tmp';
10+
import * as path from 'path';
11+
import { promisify } from 'util';
12+
import { Uri, workspace } from 'vscode';
13+
import { Oc } from '../../src/oc/ocWrapper';
14+
import { Odo } from '../../src/odo/odoWrapper';
15+
import { LoginUtil } from '../../src/util/loginUtil';
16+
import { Alizer } from '../../src/alizer/alizerWrapper';
17+
18+
suite('./alizer/alizerWrapper.ts', function () {
19+
const isOpenShift: boolean = Boolean(parseInt(process.env.IS_OPENSHIFT, 10)) || false;
20+
const clusterUrl = process.env.CLUSTER_URL || 'https://api.crc.testing:6443';
21+
const username = process.env.CLUSTER_USER || 'developer';
22+
const password = process.env.CLUSTER_PASSWORD || 'developer';
23+
24+
suiteSetup(async function () {
25+
if (isOpenShift) {
26+
try {
27+
await LoginUtil.Instance.logout();
28+
} catch {
29+
// do nothing
30+
}
31+
await Oc.Instance.loginWithUsernamePassword(clusterUrl, username, password);
32+
}
33+
});
34+
35+
suiteTeardown(async function () {
36+
// ensure projects are cleaned up
37+
try {
38+
await Oc.Instance.deleteProject('my-test-project-1');
39+
} catch {
40+
// do nothing
41+
}
42+
try {
43+
await Oc.Instance.deleteProject('my-test-project-2');
44+
} catch {
45+
// do nothing
46+
}
47+
48+
if (isOpenShift) {
49+
await LoginUtil.Instance.logout();
50+
}
51+
});
52+
53+
suite('analyse folder', function () {
54+
const project1 = 'my-test-project-1';
55+
56+
let tmpFolder1: Uri;
57+
let tmpFolder2: Uri;
58+
59+
suiteSetup(async function () {
60+
await Oc.Instance.createProject(project1);
61+
tmpFolder1 = Uri.parse(await promisify(tmp.dir)());
62+
tmpFolder2 = Uri.parse(await promisify(tmp.dir)());
63+
await Odo.Instance.createComponentFromFolder(
64+
'nodejs',
65+
undefined,
66+
'component1',
67+
tmpFolder1,
68+
'nodejs-starter',
69+
);
70+
await Odo.Instance.createComponentFromFolder(
71+
'go',
72+
undefined,
73+
'component2',
74+
tmpFolder2,
75+
'go-starter',
76+
);
77+
});
78+
79+
suiteTeardown(async function () {
80+
if (isOpenShift) {
81+
await Oc.Instance.loginWithUsernamePassword(clusterUrl, username, password);
82+
}
83+
const newWorkspaceFolders = workspace.workspaceFolders.filter((workspaceFolder) => {
84+
const fsPath = workspaceFolder.uri.fsPath;
85+
return (fsPath !== tmpFolder1.fsPath && fsPath !== tmpFolder2.fsPath);
86+
});
87+
workspace.updateWorkspaceFolders(0, workspace.workspaceFolders.length, ...newWorkspaceFolders);
88+
await fs.rm(tmpFolder1.fsPath, { force: true, recursive: true });
89+
await fs.rm(tmpFolder2.fsPath, { force: true, recursive: true });
90+
await Oc.Instance.deleteProject(project1);
91+
});
92+
93+
test('analyze()', async function () {
94+
const analysis1 = await Alizer.Instance.alizerAnalyze(tmpFolder1);
95+
expect(analysis1).to.exist;
96+
expect(analysis1.Name).to.equal('nodejs');
97+
const analysis2 = await Alizer.Instance.alizerAnalyze(tmpFolder2);
98+
expect(analysis2).to.exist;
99+
expect(analysis2.Name).to.equal('go');
100+
});
101+
});
102+
103+
suite('create component', function() {
104+
105+
const COMPONENT_TYPE = 'dotnet50';
106+
107+
let tmpFolder: string;
108+
109+
suiteSetup(async function() {
110+
tmpFolder = await promisify(tmp.dir)();
111+
});
112+
113+
suiteTeardown(async function() {
114+
await fs.rm(tmpFolder, { recursive: true, force: true });
115+
});
116+
117+
test('createComponentFromTemplateProject()', async function() {
118+
await Odo.Instance.createComponentFromTemplateProject(tmpFolder, 'my-component', 8080, COMPONENT_TYPE, 'DefaultDevfileRegistry', 'dotnet50-example');
119+
try {
120+
await fs.access(path.join(tmpFolder, 'devfile.yaml'));
121+
} catch {
122+
fail('Expected devfile to be created');
123+
}
124+
});
125+
126+
test('analyze()', async function() {
127+
const analysis = await Alizer.Instance.alizerAnalyze(Uri.file(tmpFolder));
128+
expect(analysis.Name).to.equal(COMPONENT_TYPE);
129+
});
130+
131+
});
132+
133+
test('deleteComponentConfiguration');
134+
});

test/integration/odoWrapper.test.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,6 @@ suite('./odo/odoWrapper.ts', function () {
9898
expect(componentDescription2).to.exist;
9999
expect(componentDescription2.managedBy).to.equal('odo');
100100
});
101-
102-
test('analyze()', async function () {
103-
const analysis1 = await Odo.Instance.analyze(tmpFolder1.fsPath);
104-
expect(analysis1).to.exist;
105-
expect(analysis1[0].devfile).to.equal('nodejs');
106-
const analysis2 = await Odo.Instance.analyze(tmpFolder2.fsPath);
107-
expect(analysis2).to.exist;
108-
expect(analysis2[0].devfile).to.equal('go');
109-
});
110101
});
111102

112103
suite('registries', function () {
@@ -207,12 +198,6 @@ suite('./odo/odoWrapper.ts', function () {
207198
}
208199
});
209200

210-
test('analyze()', async function() {
211-
const [analysis] = await Odo.Instance.analyze(tmpFolder);
212-
expect(analysis.name).to.equal(path.basename(tmpFolder).toLocaleLowerCase());
213-
expect(analysis.devfile).to.equal(COMPONENT_TYPE);
214-
});
215-
216201
test('deleteComponentConfiguration()', async function() {
217202
await Odo.Instance.deleteComponentConfiguration(tmpFolder);
218203
try {

0 commit comments

Comments
 (0)