Skip to content

Commit

Permalink
Show warning when unsupported Devfile features used (eclipse-che#727)
Browse files Browse the repository at this point in the history
  • Loading branch information
akurinnoy authored and ScrewTSW committed Jul 14, 2023
1 parent cf0bd89 commit 1a0f02c
Show file tree
Hide file tree
Showing 32 changed files with 661 additions and 385 deletions.
4 changes: 2 additions & 2 deletions packages/common/src/dto/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ export interface IDevWorkspaceList {
items: V1alpha2DevWorkspace[];
}

export interface IDevworkspaceResources {
export interface IDevWorkspaceResources {
devfileContent: string | undefined;
editorPath: string | undefined;
pluginRegistryUrl: string | undefined;
editorEntry: string | undefined;
editorId: string | undefined;
editorContent: string | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { api } from '@eclipse-che/common';
import { IPatch } from '@eclipse-che/common/src/dto/api';
import * as mockClient from '@kubernetes/client-node';
import { CustomObjectsApi } from '@kubernetes/client-node';
import { IncomingMessage } from 'http';
import { DevWorkspaceApiService } from '../devWorkspaceApi';

const namespace = 'user-che';
Expand All @@ -32,7 +33,10 @@ describe('DevWorkspace API Service', () => {

const stubCustomObjectsApi = {
createNamespacedCustomObject: () => {
return Promise.resolve({ body: getDevWorkspace() });
return Promise.resolve({
body: getDevWorkspace(),
response: { headers: {} } as IncomingMessage,
});
},
deleteNamespacedCustomObject: () => {
return Promise.resolve({ body: {} });
Expand All @@ -44,7 +48,10 @@ describe('DevWorkspace API Service', () => {
return Promise.resolve({ body: buildListNamespacesCustomObject() });
},
patchNamespacedCustomObject: () => {
return Promise.resolve({ body: getDevWorkspace() });
return Promise.resolve({
body: getDevWorkspace(),
response: { headers: {} } as IncomingMessage,
});
},
replaceNamespacedCustomObject: () => {
return Promise.resolve({ body: getDevWorkspace() });
Expand All @@ -71,10 +78,6 @@ describe('DevWorkspace API Service', () => {
stubCustomObjectsApi,
'patchNamespacedCustomObject',
);
const spyReplaceNamespacedCustomObject = jest.spyOn(
stubCustomObjectsApi,
'replaceNamespacedCustomObject',
);

beforeEach(() => {
const { KubeConfig } = mockClient;
Expand Down Expand Up @@ -123,7 +126,8 @@ describe('DevWorkspace API Service', () => {
} as V1alpha2DevWorkspace;

const res = await devWorkspaceService.create(devWorkspace, namespace);
expect(res).toEqual(getDevWorkspace());
expect(res.devWorkspace).toStrictEqual(getDevWorkspace());
expect(res.headers).toStrictEqual({});
expect(spyCreateNamespacedCustomObject).toHaveBeenCalledWith(
devworkspaceGroup,
devworkspaceLatestVersion,
Expand All @@ -143,7 +147,8 @@ describe('DevWorkspace API Service', () => {
];

const res = await devWorkspaceService.patch(namespace, name, patches);
expect(res).toEqual(getDevWorkspace());
expect(res.devWorkspace).toStrictEqual(getDevWorkspace());
expect(res.headers).toStrictEqual({});
expect(spyPatchNamespacedCustomObject).toHaveBeenCalledWith(
devworkspaceGroup,
devworkspaceLatestVersion,
Expand All @@ -158,28 +163,6 @@ describe('DevWorkspace API Service', () => {
);
});

test('updating', async () => {
const devWorkspace = {
apiVersion: 'workspace.devfile.io/v1alpha2',
kind: 'DevWorkspace',
metadata: {
name: 'wksp-name',
namespace,
},
} as V1alpha2DevWorkspace;

const res = await devWorkspaceService.update(devWorkspace);
expect(res).toEqual(getDevWorkspace());
expect(spyReplaceNamespacedCustomObject).toHaveBeenCalledWith(
devworkspaceGroup,
devworkspaceLatestVersion,
namespace,
devworkspacePlural,
devWorkspace.metadata?.name,
devWorkspace,
);
});

test('deleting', async () => {
await devWorkspaceService.delete(namespace, name);
expect(spyDeleteNamespacedCustomObject).toHaveBeenCalledWith(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import { api } from '@eclipse-che/common';
import * as k8s from '@kubernetes/client-node';
import { V1Status } from '@kubernetes/client-node';
import http from 'http';
import http, { IncomingHttpHeaders } from 'http';
import { MessageListener } from '../../services/types/Observer';
import { IDevWorkspaceApi } from '../types';
import { createError } from './helpers/createError';
Expand Down Expand Up @@ -71,10 +71,21 @@ export class DevWorkspaceApiService implements IDevWorkspaceApi {
}
}

private propagateHeaders(resp: { response: http.IncomingMessage; body: unknown }) {
const propagateHeaders = ['warning'];
const headers = Object.entries(resp.response.headers).reduce((acc, [key, value]) => {
if (propagateHeaders.includes(key)) {
acc[key] = value;
}
return acc;
}, {} as Partial<IncomingHttpHeaders>);
return headers;
}

async create(
devworkspace: V1alpha2DevWorkspace,
namespace: string,
): Promise<V1alpha2DevWorkspace> {
): Promise<{ devWorkspace: V1alpha2DevWorkspace; headers: Partial<IncomingHttpHeaders> }> {
try {
if (!devworkspace.metadata?.name && !devworkspace.metadata?.generateName) {
throw new Error(
Expand All @@ -89,46 +100,14 @@ export class DevWorkspaceApiService implements IDevWorkspaceApi {
devworkspacePlural,
devworkspace,
);
return resp.body as V1alpha2DevWorkspace;
const devWorkspace = resp.body as V1alpha2DevWorkspace;
const headers = this.propagateHeaders(resp);
return { devWorkspace, headers };
} catch (e) {
throw createError(e, DEV_WORKSPACE_API_ERROR_LABEL, 'Unable to create devworkspace');
}
}

async update(devworkspace: V1alpha2DevWorkspace): Promise<V1alpha2DevWorkspace> {
try {
if (!devworkspace.metadata?.name || !devworkspace.metadata?.namespace) {
throw new Error('DevWorkspace.metadata with name and namespace are required');
}

// you have to delete some elements from the devworkspace in order to update
if (devworkspace.metadata?.uid) {
devworkspace.metadata.uid = undefined;
}
if (devworkspace.metadata?.creationTimestamp) {
delete devworkspace.metadata.creationTimestamp;
}
if (devworkspace.metadata?.deletionTimestamp) {
delete devworkspace.metadata.deletionTimestamp;
}

const name = devworkspace.metadata.name;
const namespace = devworkspace.metadata.namespace;

const resp = await this.customObjectAPI.replaceNamespacedCustomObject(
devworkspaceGroup,
devworkspaceLatestVersion,
namespace,
devworkspacePlural,
name,
devworkspace,
);
return resp.body as V1alpha2DevWorkspace;
} catch (e) {
throw createError(e, DEV_WORKSPACE_API_ERROR_LABEL, 'Unable to update devworkspace');
}
}

async delete(namespace: string, name: string): Promise<void> {
try {
await this.customObjectAPI.deleteNamespacedCustomObject(
Expand All @@ -154,11 +133,7 @@ export class DevWorkspaceApiService implements IDevWorkspaceApi {
namespace: string,
name: string,
patches: api.IPatch[],
): Promise<V1alpha2DevWorkspace> {
return this.createPatch(namespace, name, patches);
}

private async createPatch(namespace: string, name: string, patches: api.IPatch[]) {
): Promise<{ devWorkspace: V1alpha2DevWorkspace; headers: Partial<IncomingHttpHeaders> }> {
try {
const options = {
headers: {
Expand All @@ -177,7 +152,9 @@ export class DevWorkspaceApiService implements IDevWorkspaceApi {
undefined,
options,
);
return resp.body as V1alpha2DevWorkspace;
const devWorkspace = resp.body as V1alpha2DevWorkspace;
const headers = this.propagateHeaders(resp);
return { devWorkspace, headers };
} catch (e) {
throw createError(e, DEV_WORKSPACE_API_ERROR_LABEL, 'Unable to patch devworkspace');
}
Expand Down
21 changes: 12 additions & 9 deletions packages/dashboard-backend/src/devworkspaceClient/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { api } from '@eclipse-che/common';
import * as k8s from '@kubernetes/client-node';
import { MessageListener } from '../../services/types/Observer';
import { IncomingHttpHeaders } from 'http';

/**
* Holds the methods for working with dockerconfig for devworkspace
Expand Down Expand Up @@ -49,19 +50,17 @@ export interface IDevWorkspaceApi extends IWatcherService {
getByName(namespace: string, name: string): Promise<V1alpha2DevWorkspace>;

/**
* Get list of devworkspaces in the given namespace
* Get list of DevWorkspaces in the given namespace
*/
listInNamespace(namespace: string): Promise<api.IDevWorkspaceList>;

/**
* Create a devworkspace based on the specified configuration.
* Create a DevWorkspace based on the specified configuration.
*/
create(devworkspace: V1alpha2DevWorkspace, namespace: string): Promise<V1alpha2DevWorkspace>;

/**
* Updates the DevWorkspace with the given configuration
*/
update(devworkspace: V1alpha2DevWorkspace): Promise<V1alpha2DevWorkspace>;
create(
devWorkspace: V1alpha2DevWorkspace,
namespace: string,
): Promise<{ devWorkspace: V1alpha2DevWorkspace; headers: Partial<IncomingHttpHeaders> }>;

/**
* Delete the DevWorkspace with given name in the specified namespace
Expand All @@ -71,7 +70,11 @@ export interface IDevWorkspaceApi extends IWatcherService {
/**
* Patches the DevWorkspace with given name in the specified namespace
*/
patch(namespace: string, name: string, patches: api.IPatch[]): Promise<V1alpha2DevWorkspace>;
patch(
namespace: string,
name: string,
patches: api.IPatch[],
): Promise<{ devWorkspace: V1alpha2DevWorkspace; headers: Partial<IncomingHttpHeaders> }>;
}

export interface IEventApi extends IWatcherService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ export function registerDevworkspaceResourcesRoute(server: FastifyInstance) {
`${baseApiPath}/devworkspace-resources`,
getSchema({ tags, body: devWorkspaceResourcesSchema }),
async function (request: FastifyRequest) {
const { devfileContent, editorPath, pluginRegistryUrl, editorEntry, editorContent } =
request.body as api.IDevworkspaceResources;
const { devfileContent, editorPath, pluginRegistryUrl, editorId, editorContent } =
request.body as api.IDevWorkspaceResources;
const context = await generator.generateDevfileContext(
{
devfileContent,
editorPath,
pluginRegistryUrl,
editorEntry,
editorEntry: editorId,
editorContent,
projects: [],
},
Expand Down
18 changes: 14 additions & 4 deletions packages/dashboard-backend/src/routes/api/devworkspaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function registerDevworkspacesRoutes(server: FastifyInstance) {
server.post(
`${baseApiPath}/namespace/:namespace/devworkspaces`,
getSchema({ tags, params: namespacedSchema, body: devworkspaceSchema }),
async function (request: FastifyRequest) {
async function (request: FastifyRequest, reply: FastifyReply) {
const { devworkspace } = request.body as restParams.IDevWorkspaceSpecParams;
const { namespace } = request.params as restParams.INamespacedParams;
if (!devworkspace.metadata) {
Expand All @@ -53,7 +53,10 @@ export function registerDevworkspacesRoutes(server: FastifyInstance) {
devworkspace.metadata.namespace = namespace;
const token = getToken(request);
const { devworkspaceApi } = getDevWorkspaceClient(token);
return devworkspaceApi.create(devworkspace, namespace);
const { headers, devWorkspace } = await devworkspaceApi.create(devworkspace, namespace);

reply.headers(headers);
reply.send(devWorkspace);
},
);

Expand All @@ -71,12 +74,19 @@ export function registerDevworkspacesRoutes(server: FastifyInstance) {
server.patch(
`${baseApiPath}/namespace/:namespace/devworkspaces/:workspaceName`,
getSchema({ tags, params: namespacedWorkspaceSchema, body: devworkspacePatchSchema }),
async function (request: FastifyRequest) {
async function (request: FastifyRequest, reply: FastifyReply) {
const { namespace, workspaceName } = request.params as restParams.INamespacedWorkspaceParams;
const patch = request.body as api.IPatch[];
const token = getToken(request);
const { devworkspaceApi } = getDevWorkspaceClient(token);
return devworkspaceApi.patch(namespace, workspaceName, patch);
const { headers, devWorkspace } = await devworkspaceApi.patch(
namespace,
workspaceName,
patch,
);

reply.headers(headers);
reply.send(devWorkspace);
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
V221DevfileComponents,
} from '@devfile/api';
import { api } from '@eclipse-che/common';
import { IncomingHttpHeaders } from 'http';
import {
DevWorkspaceClient,
IDevWorkspaceApi,
Expand Down Expand Up @@ -56,6 +57,7 @@ export const stubDevWorkspace: V1alpha2DevWorkspace = {
apiVersion: 'workspace.devfile.io/v1alpha2',
kind: 'DevWorkspace',
};
export const stubHeaders: IncomingHttpHeaders = {};

export const stubDevWorkspaceTemplatesList = [
{
Expand Down Expand Up @@ -95,11 +97,13 @@ export function getDevWorkspaceClient(_args: Parameters<typeof helper>): ReturnT
getWorkspaceStartTimeout: _cheCustomResource => stubWorkspaceStartupTimeout,
} as IServerConfigApi,
devworkspaceApi: {
create: (_devworkspace, _namespace) => Promise.resolve(stubDevWorkspace),
create: (_devworkspace, _namespace) =>
Promise.resolve({ devWorkspace: stubDevWorkspace, headers: stubHeaders }),
delete: (_namespace, _name) => Promise.resolve(undefined),
getByName: (_namespace, _name) => Promise.resolve(stubDevWorkspace),
listInNamespace: _namespace => Promise.resolve(stubDevWorkspacesList),
patch: (_namespace, _name, _patches) => Promise.resolve(stubDevWorkspace),
patch: (_namespace, _name, _patches) =>
Promise.resolve({ devWorkspace: stubDevWorkspace, headers: stubHeaders }),
} as IDevWorkspaceApi,
dockerConfigApi: {
read: _namespace => Promise.resolve(stubDockerConfig),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ exports[`Loader Progress Step INITIALIZATION snapshot 1`] = `
<svg
aria-hidden={true}
aria-labelledby={null}
className="rotate stepIcon"
className="inProgressIcon rotate stepIcon"
data-testid="step-in-progress-icon"
fill="#0e6fe0"
fill="currentColor"
height="1em"
role="img"
style={
Expand Down Expand Up @@ -135,9 +135,9 @@ exports[`Loader Progress Step INITIALIZATION snapshot 1`] = `
<svg
aria-hidden={true}
aria-labelledby={null}
className="rotate stepIcon"
className="inProgressIcon rotate stepIcon"
data-testid="step-in-progress-icon"
fill="#0e6fe0"
fill="currentColor"
height="1em"
role="img"
style={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ export class LoaderProgress extends React.PureComponent<Props> {
this.wizardRef = React.createRef();
}

public componentDidUpdate(): void {
const { currentStepId } = this.props;
const wizardCurrent = this.wizardRef.current;
if (wizardCurrent?.state?.currentStep !== currentStepId) {
wizardCurrent.state.currentStep = currentStepId;
}
}

render(): React.ReactNode {
const { currentStepId, steps } = this.props;

Expand Down
Loading

0 comments on commit 1a0f02c

Please sign in to comment.