@eclipse-che/che-devworkspace-generator 0.0.1-09a1f81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +50 -0
  2. package/lib/api/devfile-context.d.ts +19 -0
  3. package/lib/api/devfile-context.js +3 -0
  4. package/lib/api/devfile-context.js.map +1 -0
  5. package/lib/devfile/dev-container-component-finder.d.ts +17 -0
  6. package/lib/devfile/dev-container-component-finder.js +93 -0
  7. package/lib/devfile/dev-container-component-finder.js.map +1 -0
  8. package/lib/devfile/devfile-module.d.ts +12 -0
  9. package/lib/devfile/devfile-module.js +19 -0
  10. package/lib/devfile/devfile-module.js.map +1 -0
  11. package/lib/entrypoint.d.ts +11 -0
  12. package/lib/entrypoint.js +67 -0
  13. package/lib/entrypoint.js.map +1 -0
  14. package/lib/fetch/fetch-module.d.ts +12 -0
  15. package/lib/fetch/fetch-module.js +19 -0
  16. package/lib/fetch/fetch-module.js.map +1 -0
  17. package/lib/fetch/url-fetcher.d.ts +9 -0
  18. package/lib/fetch/url-fetcher.js +114 -0
  19. package/lib/fetch/url-fetcher.js.map +1 -0
  20. package/lib/generate.d.ts +16 -0
  21. package/lib/generate.js +183 -0
  22. package/lib/generate.js.map +1 -0
  23. package/lib/github/github-module.d.ts +12 -0
  24. package/lib/github/github-module.js +19 -0
  25. package/lib/github/github-module.js.map +1 -0
  26. package/lib/github/github-resolver.d.ts +18 -0
  27. package/lib/github/github-resolver.js +56 -0
  28. package/lib/github/github-resolver.js.map +1 -0
  29. package/lib/github/github-url.d.ts +29 -0
  30. package/lib/github/github-url.js +47 -0
  31. package/lib/github/github-url.js.map +1 -0
  32. package/lib/inversify/inversify-binding.d.ts +26 -0
  33. package/lib/inversify/inversify-binding.js +78 -0
  34. package/lib/inversify/inversify-binding.js.map +1 -0
  35. package/lib/main.d.ts +36 -0
  36. package/lib/main.js +265 -0
  37. package/lib/main.js.map +1 -0
  38. package/lib/plugin-registry/plugin-registry-module.d.ts +12 -0
  39. package/lib/plugin-registry/plugin-registry-module.js +19 -0
  40. package/lib/plugin-registry/plugin-registry-module.js.map +1 -0
  41. package/lib/plugin-registry/plugin-registry-resolver.d.ts +17 -0
  42. package/lib/plugin-registry/plugin-registry-resolver.js +113 -0
  43. package/lib/plugin-registry/plugin-registry-resolver.js.map +1 -0
  44. package/package.json +93 -0
  45. package/src/api/devfile-context.ts +28 -0
  46. package/src/devfile/dev-container-component-finder.ts +45 -0
  47. package/src/devfile/devfile-module.ts +18 -0
  48. package/src/entrypoint.ts +22 -0
  49. package/src/fetch/fetch-module.ts +18 -0
  50. package/src/fetch/url-fetcher.ts +49 -0
  51. package/src/generate.ts +122 -0
  52. package/src/github/github-module.ts +18 -0
  53. package/src/github/github-resolver.ts +43 -0
  54. package/src/github/github-url.ts +47 -0
  55. package/src/inversify/inversify-binding.ts +46 -0
  56. package/src/main.ts +212 -0
  57. package/src/plugin-registry/plugin-registry-module.ts +18 -0
  58. package/src/plugin-registry/plugin-registry-resolver.ts +36 -0
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**********************************************************************
3
+ * Copyright (c) 2022 Red Hat, Inc.
4
+ *
5
+ * This program and the accompanying materials are made
6
+ * available under the terms of the Eclipse Public License 2.0
7
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
8
+ *
9
+ * SPDX-License-Identifier: EPL-2.0
10
+ ***********************************************************************/
11
+
12
+ import 'reflect-metadata';
13
+
14
+ import { Main } from './main';
15
+
16
+ (async (): Promise<void> => {
17
+ const main = new Main();
18
+ const success = await main.start();
19
+ if (!success) {
20
+ process.exit(1);
21
+ }
22
+ })();
@@ -0,0 +1,18 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+ import { ContainerModule, interfaces } from 'inversify';
11
+
12
+ import { UrlFetcher } from './url-fetcher';
13
+
14
+ const fetchModule = new ContainerModule((bind: interfaces.Bind) => {
15
+ bind(UrlFetcher).toSelf().inSingletonScope();
16
+ });
17
+
18
+ export { fetchModule };
@@ -0,0 +1,49 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+ import { inject, injectable } from 'inversify';
11
+
12
+ import { AxiosInstance } from 'axios';
13
+
14
+ /**
15
+ * Allow to grab external content
16
+ * if browser support is enabled, it will update URLs to make them work on browser side.
17
+ */
18
+ @injectable()
19
+ export class UrlFetcher {
20
+ // Can't use AxiosInstance interface there
21
+ @inject(Symbol.for('AxiosInstance'))
22
+ private axiosInstance: AxiosInstance;
23
+
24
+ // fetch content optionally, if the URL is not found, we return undefined without throwing errors
25
+ async fetchTextOptionalContent(url: string): Promise<string | undefined> {
26
+ try {
27
+ const response = await this.axiosInstance.get<string>(url, {
28
+ responseType: 'text',
29
+ });
30
+ return response.data;
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ } catch (error: any) {
33
+ // not found then we return undefined
34
+ if (error.response && error.response.status === 404) {
35
+ return undefined;
36
+ }
37
+ throw error;
38
+ }
39
+ }
40
+
41
+ // fetch content
42
+ async fetchText(url: string): Promise<string> {
43
+ const response = await this.axiosInstance.get<string>(url, {
44
+ responseType: 'text',
45
+ });
46
+ return response.data;
47
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
+ }
49
+ }
@@ -0,0 +1,122 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+
11
+ import {
12
+ V1alpha2DevWorkspace,
13
+ V1alpha2DevWorkspaceSpecContributions,
14
+ V1alpha2DevWorkspaceSpecTemplateComponents,
15
+ V1alpha2DevWorkspaceTemplate,
16
+ V1alpha2DevWorkspaceTemplateSpec,
17
+ } from '@devfile/api';
18
+ import { injectable, inject } from 'inversify';
19
+ import * as jsYaml from 'js-yaml';
20
+ import * as fs from 'fs-extra';
21
+ import { DevfileContext } from './api/devfile-context';
22
+ import { DevContainerComponentFinder } from './devfile/dev-container-component-finder';
23
+
24
+ @injectable()
25
+ export class Generate {
26
+ static readonly MERGE_CONTRIBUTION = 'controller.devfile.io/merge-contribution';
27
+
28
+ @inject(DevContainerComponentFinder)
29
+ private devContainerComponentFinder: DevContainerComponentFinder;
30
+
31
+ async generate(devfileContent: string, editorContent: string, outputFile?: string): Promise<DevfileContext> {
32
+ const context = await this.generateContent(devfileContent, editorContent);
33
+
34
+ // write the result
35
+ if (outputFile) {
36
+ // write templates and then DevWorkspace in a single file
37
+ const allContentArray = context.devWorkspaceTemplates.map(template => jsYaml.dump(template));
38
+ allContentArray.push(jsYaml.dump(context.devWorkspace));
39
+
40
+ const generatedContent = allContentArray.join('---\n');
41
+
42
+ await fs.writeFile(outputFile, generatedContent, 'utf-8');
43
+ }
44
+
45
+ console.log(`DevWorkspace ${context.devWorkspaceTemplates[0].metadata.name} was generated.`);
46
+ return context;
47
+ }
48
+
49
+ async generateContent(devfileContent: string, editorContent: string): Promise<DevfileContext> {
50
+ const devfile = jsYaml.load(devfileContent);
51
+
52
+ // const originalDevfile = Object.assign({}, devfile);
53
+ // sets the suffix to the devfile name
54
+ const suffix = devfile.metadata.name || '';
55
+
56
+ // devfile of the editor
57
+ const editorDevfile = jsYaml.load(editorContent);
58
+
59
+ // transform it into a devWorkspace template
60
+ const metadata = editorDevfile.metadata;
61
+ // add sufix
62
+ metadata.name = `${metadata.name}-${suffix}`;
63
+ delete editorDevfile.metadata;
64
+ delete editorDevfile.schemaVersion;
65
+ const editorDevWorkspaceTemplate: V1alpha2DevWorkspaceTemplate = {
66
+ apiVersion: 'workspace.devfile.io/v1alpha2',
67
+ kind: 'DevWorkspaceTemplate',
68
+ metadata,
69
+ spec: editorDevfile as V1alpha2DevWorkspaceTemplateSpec,
70
+ };
71
+
72
+ // transform it into a devWorkspace
73
+ const devfileMetadata = devfile.metadata;
74
+ const devfileCopy = Object.assign({}, devfile);
75
+ delete devfileCopy.schemaVersion;
76
+ delete devfileCopy.metadata;
77
+ const editorSpecContribution: V1alpha2DevWorkspaceSpecContributions = {
78
+ name: 'editor',
79
+ kubernetes: {
80
+ name: editorDevWorkspaceTemplate.metadata.name,
81
+ },
82
+ };
83
+ const devWorkspace: V1alpha2DevWorkspace = {
84
+ apiVersion: 'workspace.devfile.io/v1alpha2',
85
+ kind: 'DevWorkspace',
86
+ metadata: devfileMetadata,
87
+ spec: {
88
+ started: true,
89
+ template: devfileCopy,
90
+ contributions: [editorSpecContribution],
91
+ },
92
+ };
93
+
94
+ // for now the list of devWorkspace templates is only the editor template
95
+ const devWorkspaceTemplates = [editorDevWorkspaceTemplate];
96
+
97
+ const context = {
98
+ devfile,
99
+ devWorkspace,
100
+ devWorkspaceTemplates,
101
+ suffix,
102
+ };
103
+
104
+ // grab container where to inject controller.devfile.io/merge-contribution attribute
105
+ let devContainer: V1alpha2DevWorkspaceSpecTemplateComponents = await this.devContainerComponentFinder.find(context);
106
+ if (!devContainer) {
107
+ return context;
108
+ }
109
+
110
+ // add attributes
111
+ let devContainerAttributes = devContainer.attributes;
112
+ if (!devContainerAttributes) {
113
+ devContainerAttributes = {};
114
+ devContainerAttributes[Generate.MERGE_CONTRIBUTION] = true;
115
+ devContainer.attributes = devContainerAttributes;
116
+ } else {
117
+ devContainerAttributes[Generate.MERGE_CONTRIBUTION] = true;
118
+ }
119
+
120
+ return context;
121
+ }
122
+ }
@@ -0,0 +1,18 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+ import { ContainerModule, interfaces } from 'inversify';
11
+
12
+ import { GithubResolver } from './github-resolver';
13
+
14
+ const githubModule = new ContainerModule((bind: interfaces.Bind) => {
15
+ bind(GithubResolver).toSelf().inSingletonScope();
16
+ });
17
+
18
+ export { githubModule };
@@ -0,0 +1,43 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+
11
+ import { GithubUrl } from './github-url';
12
+ import { injectable } from 'inversify';
13
+
14
+ /**
15
+ * Provides a github URL object allowing to interact
16
+ */
17
+ @injectable()
18
+ export class GithubResolver {
19
+ // eslint-disable-next-line max-len
20
+ static readonly GITHUB_URL_PATTERN =
21
+ /^(?<scheme>https?):\/\/(?<host>github(\..+)?\.[^\/]+)\/(?<repoUser>[^\/]+)\/(?<repoName>[^\/]+)((\/)|\/(blob|tree)\/(?<branchName>[^\/]+)(?:\/(?<subFolder>.*))?)?$/;
22
+
23
+ resolve(link: string): GithubUrl {
24
+ const match = GithubResolver.GITHUB_URL_PATTERN.exec(link);
25
+ if (!match) {
26
+ throw new Error(`Invalid github URL: ${link}`);
27
+ }
28
+ const scheme = this.getGroup(match, 'scheme');
29
+ const hostName = this.getGroup(match, 'host');
30
+ const repoUser = this.getGroup(match, 'repoUser');
31
+ const repoName = this.getGroup(match, 'repoName');
32
+ const branchName = this.getGroup(match, 'branchName', 'HEAD');
33
+ const subFolder = this.getGroup(match, 'subFolder');
34
+ return new GithubUrl(scheme, hostName, repoUser, repoName, branchName, subFolder);
35
+ }
36
+
37
+ getGroup(match: RegExpExecArray, groupName: string, defaultValue?: string) {
38
+ if (match.groups && match.groups[groupName]) {
39
+ return match.groups[groupName];
40
+ }
41
+ return defaultValue || '';
42
+ }
43
+ }
@@ -0,0 +1,47 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+
11
+ /**
12
+ * Provides helper methods on top of github URL to get for example raw content of get relative links
13
+ */
14
+ export class GithubUrl {
15
+ constructor(
16
+ private readonly scheme: string,
17
+ private readonly hostName: string,
18
+ private readonly repoUser: string,
19
+ private readonly repoName: string,
20
+ private readonly branchName: string,
21
+ private readonly subFolder: string
22
+ ) {}
23
+
24
+ /**
25
+ * Provides the raw link to the given path based on the current repository information
26
+ */
27
+ getContentUrl(path: string): string {
28
+ const hostName = this.hostName === 'github.com' ? 'githubusercontent.com' : this.hostName;
29
+ return `${this.scheme}://raw.${hostName}/${this.repoUser}/${this.repoName}/${this.branchName}/${path}`;
30
+ }
31
+
32
+ getUrl(): string {
33
+ return `${this.scheme}://${this.hostName}/${this.repoUser}/${this.repoName}/tree/${this.branchName}/${this.subFolder}`;
34
+ }
35
+
36
+ getCloneUrl(): string {
37
+ return `${this.scheme}://${this.hostName}/${this.repoUser}/${this.repoName}.git`;
38
+ }
39
+
40
+ getRepoName(): string {
41
+ return this.repoName;
42
+ }
43
+
44
+ getBranchName(): string {
45
+ return this.branchName;
46
+ }
47
+ }
@@ -0,0 +1,46 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+ import 'reflect-metadata';
11
+
12
+ import { AxiosInstance } from 'axios';
13
+ import { Container } from 'inversify';
14
+ import { devfileModule } from '../devfile/devfile-module';
15
+ import { fetchModule } from '../fetch/fetch-module';
16
+ import { githubModule } from '../github/github-module';
17
+ import { pluginRegistryModule } from '../plugin-registry/plugin-registry-module';
18
+
19
+ /**
20
+ * Manage all bindings for inversify
21
+ */
22
+ export class InversifyBinding {
23
+ private container: Container;
24
+
25
+ public async initBindings(options: InversifyBindingOptions): Promise<Container> {
26
+ this.container = new Container();
27
+
28
+ this.container.load(devfileModule);
29
+ this.container.load(fetchModule);
30
+ this.container.load(githubModule);
31
+ this.container.load(pluginRegistryModule);
32
+
33
+ this.container.bind(Symbol.for('AxiosInstance')).toConstantValue(options.axiosInstance);
34
+ this.container.bind('string').toConstantValue(options.pluginRegistryUrl).whenTargetNamed('PLUGIN_REGISTRY_URL');
35
+
36
+ return this.container;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Options for inversify bindings
42
+ */
43
+ export interface InversifyBindingOptions {
44
+ pluginRegistryUrl: string;
45
+ axiosInstance: AxiosInstance;
46
+ }
package/src/main.ts ADDED
@@ -0,0 +1,212 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+
11
+ import * as axios from 'axios';
12
+ import * as fs from 'fs-extra';
13
+ import { Generate } from './generate';
14
+ import { GithubResolver } from './github/github-resolver';
15
+ import * as jsYaml from 'js-yaml';
16
+ import { InversifyBinding } from './inversify/inversify-binding';
17
+ import { UrlFetcher } from './fetch/url-fetcher';
18
+ import { PluginRegistryResolver } from './plugin-registry/plugin-registry-resolver';
19
+ import { V1alpha2DevWorkspaceSpecTemplate } from '@devfile/api';
20
+ import { DevfileContext } from './api/devfile-context';
21
+
22
+ export class Main {
23
+ /**
24
+ * Default constructor.
25
+ */
26
+ constructor() {
27
+ // no-op
28
+ }
29
+ // Generates a devfile context object based on params
30
+ public async generateDevfileContext(
31
+ params: {
32
+ devfilePath?: string;
33
+ devfileUrl?: string;
34
+ devfileContent?: string;
35
+ outputFile?: string;
36
+ editorPath?: string;
37
+ editorContent?: string;
38
+ editorEntry?: string;
39
+ pluginRegistryUrl?: string;
40
+ projects: { name: string; location: string }[];
41
+ },
42
+ axiosInstance: axios.AxiosInstance
43
+ ): Promise<DevfileContext> {
44
+ if (!params.editorPath && !params.editorEntry && !params.editorContent) {
45
+ throw new Error('missing editorPath or editorEntry or editorContent');
46
+ }
47
+ if (!params.devfilePath && !params.devfileUrl && !params.devfileContent) {
48
+ throw new Error('missing devfilePath or devfileUrl or devfileContent');
49
+ }
50
+
51
+ let pluginRegistryUrl: string;
52
+
53
+ if (params.pluginRegistryUrl) {
54
+ pluginRegistryUrl = params.pluginRegistryUrl;
55
+ } else {
56
+ pluginRegistryUrl = 'https://eclipse-che.github.io/che-plugin-registry/main/v3';
57
+ console.log(`No plug-in registry url. Setting to ${pluginRegistryUrl}`);
58
+ }
59
+
60
+ const inversifyBinbding = new InversifyBinding();
61
+ const container = await inversifyBinbding.initBindings({
62
+ pluginRegistryUrl,
63
+ axiosInstance,
64
+ });
65
+ container.bind(Generate).toSelf().inSingletonScope();
66
+
67
+ let devfileContent;
68
+ let editorContent;
69
+
70
+ // gets the github URL
71
+ if (params.devfileUrl) {
72
+ const githubResolver = container.get(GithubResolver);
73
+ const githubUrl = githubResolver.resolve(params.devfileUrl);
74
+ // user devfile
75
+ devfileContent = await container.get(UrlFetcher).fetchText(githubUrl.getContentUrl('devfile.yaml'));
76
+
77
+ // load content
78
+ const devfileParsed = jsYaml.load(devfileContent);
79
+
80
+ // is there projects in the devfile ?
81
+ if (devfileParsed && !devfileParsed.projects) {
82
+ // no, so add the current project being cloned
83
+ devfileParsed.projects = [
84
+ {
85
+ name: githubUrl.getRepoName(),
86
+ git: {
87
+ remotes: { origin: githubUrl.getCloneUrl() },
88
+ checkoutFrom: { revision: githubUrl.getBranchName() },
89
+ },
90
+ },
91
+ ];
92
+ }
93
+ // get back the content
94
+ devfileContent = jsYaml.dump(devfileParsed);
95
+ } else if (params.devfilePath) {
96
+ devfileContent = await fs.readFile(params.devfilePath);
97
+ } else {
98
+ devfileContent = params.devfileContent;
99
+ }
100
+
101
+ // enhance projects
102
+ devfileContent = this.replaceIfExistingProjects(devfileContent, params.projects);
103
+
104
+ if (params.editorContent) {
105
+ editorContent = params.editorContent;
106
+ } else if (params.editorEntry) {
107
+ // devfile of the editor
108
+ const editorDevfile = await container.get(PluginRegistryResolver).loadDevfilePlugin(params.editorEntry);
109
+ editorContent = jsYaml.dump(editorDevfile);
110
+ } else {
111
+ editorContent = await fs.readFile(params.editorPath);
112
+ }
113
+
114
+ const generate = container.get(Generate);
115
+ return generate.generate(devfileContent, editorContent, params.outputFile);
116
+ }
117
+
118
+ // Update project entry based on the projects passed as parameter
119
+ public replaceIfExistingProjects(devfileContent: string, projects: { name: string; location: string }[]): string {
120
+ // do nothing if no override
121
+ if (projects.length === 0) {
122
+ return devfileContent;
123
+ }
124
+ const devfileParsed: V1alpha2DevWorkspaceSpecTemplate = jsYaml.load(devfileContent);
125
+
126
+ if (!devfileParsed || !devfileParsed.projects) {
127
+ return devfileContent;
128
+ }
129
+ devfileParsed.projects = devfileParsed.projects.map(project => {
130
+ const userProjectConfiguration = projects.find(p => p.name === project.name);
131
+ if (userProjectConfiguration) {
132
+ if (userProjectConfiguration.location.endsWith('.zip')) {
133
+ // delete git section and use instead zip
134
+ delete project.git;
135
+ project.zip = { location: userProjectConfiguration.location };
136
+ } else {
137
+ project.git.remotes.origin = userProjectConfiguration.location;
138
+ }
139
+ }
140
+ return project;
141
+ });
142
+ return jsYaml.dump(devfileParsed);
143
+ }
144
+
145
+ async start(): Promise<boolean> {
146
+ let devfilePath: string | undefined;
147
+ let devfileUrl: string | undefined;
148
+ let outputFile: string | undefined;
149
+ let editorPath: string | undefined;
150
+ let pluginRegistryUrl: string | undefined;
151
+ let editorEntry: string | undefined;
152
+ const projects: { name: string; location: string }[] = [];
153
+
154
+ const args = process.argv.slice(2);
155
+ args.forEach(arg => {
156
+ if (arg.startsWith('--devfile-path:')) {
157
+ devfilePath = arg.substring('--devfile-path:'.length);
158
+ }
159
+ if (arg.startsWith('--devfile-url:')) {
160
+ devfileUrl = arg.substring('--devfile-url:'.length);
161
+ }
162
+ if (arg.startsWith('--plugin-registry-url:')) {
163
+ pluginRegistryUrl = arg.substring('--plugin-registry-url:'.length);
164
+ }
165
+ if (arg.startsWith('--editor-entry:')) {
166
+ editorEntry = arg.substring('--editor-entry:'.length);
167
+ }
168
+ if (arg.startsWith('--editor-path:')) {
169
+ editorPath = arg.substring('--editor-path:'.length);
170
+ }
171
+ if (arg.startsWith('--output-file:')) {
172
+ outputFile = arg.substring('--output-file:'.length);
173
+ }
174
+ if (arg.startsWith('--project.')) {
175
+ const name = arg.substring('--project.'.length, arg.indexOf('='));
176
+ let location = arg.substring(arg.indexOf('=') + 1);
177
+ location = location.replace('{{_INTERNAL_URL_}}', '{{ INTERNAL_URL }}');
178
+
179
+ projects.push({ name, location });
180
+ }
181
+ });
182
+
183
+ try {
184
+ if (!editorPath && !editorEntry) {
185
+ throw new Error('missing --editor-path: or --editor-entry: parameter');
186
+ }
187
+ if (!devfilePath && !devfileUrl) {
188
+ throw new Error('missing --devfile-path: or --devfile-url: parameter');
189
+ }
190
+ if (!outputFile) {
191
+ throw new Error('missing --output-file: parameter');
192
+ }
193
+ await this.generateDevfileContext(
194
+ {
195
+ devfilePath,
196
+ devfileUrl,
197
+ editorPath,
198
+ outputFile,
199
+ pluginRegistryUrl,
200
+ editorEntry,
201
+ projects,
202
+ },
203
+ axios.default
204
+ );
205
+ return true;
206
+ } catch (error) {
207
+ console.error('stack=' + error.stack);
208
+ console.error('Unable to start', error);
209
+ return false;
210
+ }
211
+ }
212
+ }
@@ -0,0 +1,18 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+ import { ContainerModule, interfaces } from 'inversify';
11
+
12
+ import { PluginRegistryResolver } from './plugin-registry-resolver';
13
+
14
+ const pluginRegistryModule = new ContainerModule((bind: interfaces.Bind) => {
15
+ bind(PluginRegistryResolver).toSelf().inSingletonScope();
16
+ });
17
+
18
+ export { pluginRegistryModule };
@@ -0,0 +1,36 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2022 Red Hat, Inc.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ ***********************************************************************/
10
+
11
+ import * as jsYaml from 'js-yaml';
12
+
13
+ import { inject, injectable, named } from 'inversify';
14
+
15
+ import { UrlFetcher } from '../fetch/url-fetcher';
16
+
17
+ /**
18
+ * Resolve plug-ins by grabbing the definition from the plug-in registry.
19
+ */
20
+ @injectable()
21
+ export class PluginRegistryResolver {
22
+ @inject('string')
23
+ @named('PLUGIN_REGISTRY_URL')
24
+ private pluginRegistryUrl: string;
25
+
26
+ @inject(UrlFetcher)
27
+ private urlFetcher: UrlFetcher;
28
+
29
+ // FQN id (like che-incubator/che-code/next)
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ async loadDevfilePlugin(devfileId: string): Promise<any> {
32
+ const devfileUrl = `${this.pluginRegistryUrl}/plugins/${devfileId}/devfile.yaml`;
33
+ const devfileContent = await this.urlFetcher.fetchText(devfileUrl);
34
+ return jsYaml.load(devfileContent);
35
+ }
36
+ }