Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

fix(workpace-plugin): Importing several private projects in a single devfile #959

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions plugins/workspace-plugin/devfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
apiVersion: 1.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's a good practice to introduce devfiles in each directory ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This a devfile to work on the workspace plugin, as this project lives in a subdirectory of the git repo, it looks good to have it there, next to the package.json, etc ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it's part of a yarn workspace so you should use top-level folder/definitions/devfile anyway to inherits from all workspace definition

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok but isn't it overkill when a dev just want to work on 1 plugin ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be useful to have the devfile here, even just for reference purposes. It could be useful to point for new contributors in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This devfile is for coding the workspace plugin without having to rebuild che-theia and all the other plugins. It doesn't make sense to have it elsewhere.

Copy link
Contributor Author

@sunix sunix Jan 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maintenance issue is not related to the location of the devfiles. but how a devfile could be extended: so the devfile for the workspace plugin (that would be in the workspace plugin folder) could extend a more generic devfile for built-in plugins but adding its own specifics (for instance, custom commands, etc ...). Maybe it is in the scope of devfile 2.
Parent pom.xml files are usually there to share BoM. But without these sharing capabilities, we would have pom.xml files for each module that would be also hard to maintain. Anyway a module would have its own pom.xml.

Anyway, the devfile for the workspace plugin has to stay here because it would setup the right workspace for the workspace-plugin developer flow.

Copy link
Contributor Author

@sunix sunix Jan 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then if the suggestion is to move that devfile to the devfiles directory I don't see how easier it would be to maintain. Or is the suggestion not to have devfile at all and let all the developers loosing time to setup an dev environment to work on each individual plugins?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the suggestion is to have a a single devfile for developing che-theia.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is that devfile https://github.com/eclipse/che-theia/blob/master/devfiles/che-theia-all.devfile.yaml but it is doing way too many things when it is to work a a particular plugin.


metadata:
generateName: che-theia-workspace-plugin-

projects:
- name: che-theia
source:
location: 'https://github.com/eclipse/che-theia.git'
type: git

components:
- mountSources: true
command:
- tail
- '-f'
- /dev/null
memoryLimit: 512Gi
type: dockerimage
image: 'quay.io/eclipse/che-theia:next'
alias: che-theia-next-dev
env:
- value: 0.0.0.0
name: THEIA_HOST
- value: '3130'
name: THEIA_PORT
- value: '0'
name: NODE_TLS_REJECT_UNAUTHORIZED

- mountSources: true
memoryLimit: 3Gi
type: dockerimage
image: 'quay.io/eclipse/che-theia-dev:next'
alias: che-dev

- id: redhat/vscode-yaml/latest
type: chePlugin

- id: che-incubator/typescript/latest
memoryLimit: 2048M
type: chePlugin

- id: ms-vscode/vscode-github-pullrequest/latest
type: chePlugin

commands:

- name: build ... workspace-plugin
actions:
- workdir: /projects/che-theia/plugins/workspace-plugin
type: exec
command: |
killall node; yarn || (yarn lint:fix && yarn format:fix && yarn) && echo -e "\e[32mDone.\e[0m build ... workspace-plugin"
component: che-dev

- name: test-watch ... workspace-plugin
actions:
- workdir: /projects/che-theia/plugins/workspace-plugin
type: exec
command: |
killall node; yarn test:watch
component: che-dev

- name: run ... che-theia + workspace-plugin
previewUrl:
port: 3130
actions:
- workdir: /home/theia
type: exec
command: |
rm /default-theia-plugins/eclipse_che_workspace_plugin.theia; mkdir -p /tmp/theiadev_projects && export CHE_PROJECTS_ROOT=/tmp/theiadev_projects && cp /projects/che-theia/plugins/workspace-plugin/eclipse_che_workspace_plugin.theia /default-theia-plugins/ && /entrypoint.sh
component: che-theia-next-dev
1 change: 1 addition & 0 deletions plugins/workspace-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"src"
],
"dependencies": {
"async-mutex": "^0.2.6",
"fs-extra": "7.0.1"
},
"devDependencies": {
Expand Down
40 changes: 40 additions & 0 deletions plugins/workspace-plugin/src/askpass-prompt-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**********************************************************************
* Copyright (c) 2019-2021 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/
import { Mutex } from 'async-mutex';

export class PromptManager {
private askPassResults: Map<Symbol, string> = new Map();
private mutex: Mutex = new Mutex();

constructor(promptLauncher: (host: string, placeHolder: string) => PromiseLike<string | undefined>) {
this.askPassPromptLauncher = promptLauncher;
}

async askPass(host: string, placeHolder: string): Promise<string> {
const release = await this.mutex.acquire();
try {
const key = getKey(host, placeHolder);
if (this.askPassResults.has(key)) {
return this.askPassResults.get(key) || '';
}
const result = (await this.askPassPromptLauncher(host, placeHolder)) || '';
this.askPassResults.set(key, result);
return result;
} finally {
release();
}
}

askPassPromptLauncher: (host: string, placeHolder: string) => PromiseLike<string | undefined>;
}

function getKey(host: string, placeHolder: string) {
return Symbol.for(`key[${host}:${placeHolder}]`);
}
26 changes: 14 additions & 12 deletions plugins/workspace-plugin/src/askpass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import * as os from 'os';
import * as path from 'path';
import * as theia from '@theia/plugin';

import { PromptManager } from './askpass-prompt-manager';

const randomBytes = denodeify<Buffer>(crypto.randomBytes);

export interface AskpassEnvironment {
Expand Down Expand Up @@ -46,8 +48,19 @@ export class Askpass implements theia.Disposable {
private ipcHandlePath: string | undefined;
private enabled = true;

private promptManager: PromptManager;

constructor() {
this.server = http.createServer((req, res) => this.onRequest(req, res));
this.promptManager = new PromptManager((host: string, placeHolder: string) => {
const options: theia.InputBoxOptions = {
password: /password/i.test(placeHolder),
placeHolder: placeHolder,
prompt: `Git: ${host}`,
ignoreFocusOut: true,
};
return theia.window.showInputBox(options);
});
this.ipcHandlePathPromise = this.setup().catch(err => {
console.error(err);
return '';
Expand Down Expand Up @@ -78,7 +91,7 @@ export class Askpass implements theia.Disposable {
req.on('end', () => {
const { request, host } = JSON.parse(chunks.join(''));

this.prompt(host, request).then(
this.promptManager.askPass(host, request).then(
result => {
res.writeHead(200);
res.end(JSON.stringify(result));
Expand All @@ -91,17 +104,6 @@ export class Askpass implements theia.Disposable {
});
}

private async prompt(host: string, request: string): Promise<string> {
const options: theia.InputBoxOptions = {
password: /password/i.test(request),
placeHolder: request,
prompt: `Git: ${host}`,
ignoreFocusOut: true,
};

return (await theia.window.showInputBox(options)) || '';
}

async getEnv(): Promise<AskpassEnvironment> {
if (!this.enabled) {
return {
Expand Down
52 changes: 52 additions & 0 deletions plugins/workspace-plugin/tests/askpass-prompt-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**********************************************************************
* Copyright (c) 2019-2021 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import { PromptManager } from '../src/askpass-prompt-manager';

describe('testing async prompt request', () => {
let iteration: number;
let promptManager: PromptManager;

beforeEach(() => {
iteration = 0;
promptManager = new PromptManager(
(host: string, placeHolder: string) =>
new Promise(resolve => {
iteration += 1;
setTimeout(resolve, Math.floor(Math.random() * 500) + 1000);
console.log(`resolving ${host} ${placeHolder} iteration: ${iteration}`);
resolve(`hello ${host} ${placeHolder} - iteration: ${iteration}`);
})
);
});

test('the prompt promise should be executed in sequence in the call order', async () => {
const askpass1promise = promptManager.askPass('host', 'username');
const askpass2promise = promptManager.askPass('host', 'password');
expect(await askpass2promise).toBe('hello host password - iteration: 2');
expect(await askpass1promise).toBe('hello host username - iteration: 1');
});

test('a prompt with the same host and placeHolder should return the same value and not be executed twice', async () => {
const askpass1promise = promptManager.askPass('host', 'username');
const askpass2promise = promptManager.askPass('host', 'password');
const askpass1promise_bis = promptManager.askPass('host', 'username');
const askpass3promise = promptManager.askPass('host2', 'username');
const askpass4promise = promptManager.askPass('host2', 'password');
const askpass3promise_bis = promptManager.askPass('host2', 'username');

expect(await askpass2promise).toBe('hello host password - iteration: 2');
expect(await askpass3promise).toBe('hello host2 username - iteration: 3');
expect(await askpass1promise).toBe('hello host username - iteration: 1');
expect(await askpass1promise_bis).toBe('hello host username - iteration: 1');
expect(await askpass4promise).toBe('hello host2 password - iteration: 4');
expect(await askpass3promise_bis).toBe('hello host2 username - iteration: 3');
});
});
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4156,6 +4156,13 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==

async-mutex@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.2.6.tgz#0d7a3deb978bc2b984d5908a2038e1ae2e54ff40"
integrity sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==
dependencies:
tslib "^2.0.0"

async@^2.0.0, async@^2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
Expand Down Expand Up @@ -14828,6 +14835,11 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

tslib@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==

tsutils@^3.0.0, tsutils@^3.17.1:
version "3.18.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.18.0.tgz#38add50a28ec97e988cb43c5b32e55d1ff4a222a"
Expand Down