Skip to content
Open
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
139 changes: 139 additions & 0 deletions workspaces/x2a/plugins/x2a-backend/src/schema/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,108 @@ paths:
'404':
description: Project or job not found

/projects/{projectId}/devspaces:
get:
summary: Returns the DevSpaces workspace for a project
description: |
Retrieves the OpenShift Dev Spaces workspace associated with the project.
Returns 404 if no workspace exists for this project.
parameters:
- in: path
name: projectId
schema:
type: string
required: true
description: UUID of the project
responses:
'200':
description: DevSpaces workspace information
content:
application/json:
schema:
$ref: '#/components/schemas/DevSpacesWorkspace'
'404':
description: No DevSpaces workspace exists for this project

post:
summary: Creates a DevSpaces workspace for a project
description: |
Creates an OpenShift Dev Spaces workspace for Ansible development.
If a workspace already exists for this project, returns the existing workspace (idempotent).

The workspace will:
- Clone the project's target repository (where migrated Ansible code lives)
- Provide a browser-based IDE (VS Code) with Ansible tooling
- Be accessible via the URL returned in the response once status reaches 'running'
parameters:
- in: path
name: projectId
schema:
type: string
required: true
description: UUID of the project
responses:
'201':
description: DevSpaces workspace created successfully
content:
application/json:
schema:
type: object
properties:
id:
type: string
description: UUID of the created workspace
status:
$ref: '#/components/schemas/DevSpacesWorkspaceStatus'
message:
type: string
description: Confirmation message
required:
- id
- status
- message
'200':
description: DevSpaces workspace already exists (idempotent)
content:
application/json:
schema:
$ref: '#/components/schemas/DevSpacesWorkspace'
'404':
description: Project not found
'409':
description: Workspace is being deleted, cannot create yet

delete:
summary: Deletes the DevSpaces workspace for a project
description: |
Stops and deletes the OpenShift Dev Spaces workspace associated with the project.
This removes the Kubernetes DevWorkspace resource and all associated data.
parameters:
- in: path
name: projectId
schema:
type: string
required: true
description: UUID of the project
responses:
'200':
description: DevSpaces workspace deleted successfully
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Confirmation message
deletedWorkspaceId:
type: string
description: UUID of the deleted workspace
required:
- message
'404':
description: No DevSpaces workspace exists for this project

Comment on lines +535 to +636
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Devspaces endpoints unimplemented 🐞 Bug ✓ Correctness

The PR adds /projects/{projectId}/devspaces GET/POST/DELETE to the OpenAPI spec and generates
client/server types, but the backend does not register any Express handlers for these routes, so
requests will return 404 at runtime.
Agent Prompt
### Issue description
The OpenAPI contract and generated clients expose `/projects/{projectId}/devspaces` GET/POST/DELETE, but the backend router does not implement these routes, causing runtime 404s.

### Issue Context
`createRouter` mounts an OpenAPI router and registers only projects/modules/jobs routes today.

### Fix Focus Areas
- Implement and register GET/POST/DELETE handlers for the new path (even as explicit placeholders that return 501) so the route exists and behavior is deterministic.
- Ensure handlers enforce the same auth/permission model as other project-scoped endpoints.

- workspaces/x2a/plugins/x2a-backend/src/router/index.ts[32-52]
- workspaces/x2a/plugins/x2a-backend/src/router/projects.ts[53-383]
- workspaces/x2a/plugins/x2a-backend/src/schema/openapi.yaml[535-636]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

components:
securitySchemes:
callbackSignature:
Expand Down Expand Up @@ -909,3 +1011,40 @@ components:
required:
- name
- durationSeconds

DevSpacesWorkspaceStatus:
type: string
enum:
- starting
- running
- stopped
- failed
description: |
Status of the DevSpaces workspace:
- starting: Workspace is being provisioned (pod creation, image pull, networking)
- running: Workspace is ready and accessible via URL
- stopped: Workspace has been stopped but not deleted
- failed: Workspace provisioning or runtime failed

DevSpacesWorkspace:
type: object
properties:
id:
type: string
description: UUID for the DevSpaces workspace
status:
$ref: '#/components/schemas/DevSpacesWorkspaceStatus'
url:
type: string
description: IDE access URL (only present when status is 'running')
createdAt:
type: string
format: date-time
description: Date/time when the workspace was created
errorDetails:
type: string
description: Error information if status is 'failed'
required:
- id
- status
- createdAt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// ******************************************************************
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
// ******************************************************************
import { DevSpacesWorkspace } from '../models/DevSpacesWorkspace.model';
import { MigrationPhase } from '../models/MigrationPhase.model';
import { Module } from '../models/Module.model';
import { ModulePhase } from '../models/ModulePhase.model';
Expand All @@ -28,6 +29,8 @@
import { ProjectsProjectIdCollectArtifactsPost200Response } from '../models/ProjectsProjectIdCollectArtifactsPost200Response.model';
import { ProjectsProjectIdCollectArtifactsPostRequest } from '../models/ProjectsProjectIdCollectArtifactsPostRequest.model';
import { ProjectsProjectIdDelete200Response } from '../models/ProjectsProjectIdDelete200Response.model';
import { ProjectsProjectIdDevspacesDelete200Response } from '../models/ProjectsProjectIdDevspacesDelete200Response.model';
import { ProjectsProjectIdDevspacesPost201Response } from '../models/ProjectsProjectIdDevspacesPost201Response.model';
import { ProjectsProjectIdModulesModuleIdCancelPostRequest } from '../models/ProjectsProjectIdModulesModuleIdCancelPostRequest.model';
import { ProjectsProjectIdModulesModuleIdRunPostRequest } from '../models/ProjectsProjectIdModulesModuleIdRunPostRequest.model';
import { ProjectsProjectIdModulesPostRequest } from '../models/ProjectsProjectIdModulesPostRequest.model';
Expand Down Expand Up @@ -85,6 +88,37 @@
};
response: ProjectsProjectIdDelete200Response;
};
/**
* @public
*/
export type ProjectsProjectIdDevspacesDelete = {
path: {
projectId: string;
};
response: ProjectsProjectIdDevspacesDelete200Response | void;
};
/**
* @public
*/
export type ProjectsProjectIdDevspacesGet = {
path: {
projectId: string;
};
response: DevSpacesWorkspace | void;
};
/**
* @public
*/
export type ProjectsProjectIdDevspacesPost = {
path: {
projectId: string;
};
response:
| ProjectsProjectIdDevspacesPost201Response
| DevSpacesWorkspace
| void
| void;

Check failure on line 120 in workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/apis/Api.server.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this duplicated type or replace with another one.

See more on https://sonarcloud.io/project/issues?id=redhat-developer_rhdh-plugins&issues=AZ0fLYyIIEY-Pb8p-Xwv&open=AZ0fLYyIIEY-Pb8p-Xwv&pullRequest=2594
Comment on lines +119 to +120
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

duplicate? adding an error response body schema to 404/409 would produce cleaner types

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We spoke here offline, the reason of not having a message here, it's because the error are self explanatory, so the frontend can take the error by itself, and apply the translation correctly.

};
/**
* @public
*/
Expand Down Expand Up @@ -191,6 +225,12 @@

'#_delete|/projects/{projectId}': ProjectsProjectIdDelete;

'#_delete|/projects/{projectId}/devspaces': ProjectsProjectIdDevspacesDelete;

'#get|/projects/{projectId}/devspaces': ProjectsProjectIdDevspacesGet;

'#post|/projects/{projectId}/devspaces': ProjectsProjectIdDevspacesPost;

'#get|/projects/{projectId}': ProjectsProjectIdGet;

'#get|/projects/{projectId}/log': ProjectsProjectIdLogGet;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// ******************************************************************
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
// ******************************************************************
import { DevSpacesWorkspaceStatus } from '../models/DevSpacesWorkspaceStatus.model';

/**
* @public
*/
export interface DevSpacesWorkspace {
/**
* UUID for the DevSpaces workspace
*/
id: string;
status: DevSpacesWorkspaceStatus;
/**
* IDE access URL (only present when status is 'running')
*/
url?: string;
/**
* Date/time when the workspace was created
*/
createdAt: Date;
/**
* Error information if status is 'failed'
*/
errorDetails?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// ******************************************************************
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
// ******************************************************************

/**
* @public
*/
export type DevSpacesWorkspaceStatus =
| 'starting'
| 'running'
| 'stopped'
| 'failed';
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// ******************************************************************
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
// ******************************************************************

/**
* @public
*/
export interface ProjectsProjectIdDevspacesDelete200Response {
/**
* Confirmation message
*/
message: string;
/**
* UUID of the deleted workspace
*/
deletedWorkspaceId?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// ******************************************************************
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
// ******************************************************************
import { DevSpacesWorkspaceStatus } from '../models/DevSpacesWorkspaceStatus.model';

/**
* @public
*/
export interface ProjectsProjectIdDevspacesPost201Response {
/**
* UUID of the created workspace
*/
id: string;
status: DevSpacesWorkspaceStatus;
/**
* Confirmation message
*/
message: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export * from '../models/AAPCredentials.model';
export * from '../models/AgentMetrics.model';
export * from '../models/Artifact.model';
export * from '../models/ArtifactType.model';
export * from '../models/DevSpacesWorkspace.model';
export * from '../models/DevSpacesWorkspaceStatus.model';
export * from '../models/GitRepoAuth.model';
export * from '../models/Job.model';
export * from '../models/JobStatusEnum.model';
Expand All @@ -34,6 +36,8 @@ export * from '../models/ProjectsPostRequest.model';
export * from '../models/ProjectsProjectIdCollectArtifactsPost200Response.model';
export * from '../models/ProjectsProjectIdCollectArtifactsPostRequest.model';
export * from '../models/ProjectsProjectIdDelete200Response.model';
export * from '../models/ProjectsProjectIdDevspacesDelete200Response.model';
export * from '../models/ProjectsProjectIdDevspacesPost201Response.model';
export * from '../models/ProjectsProjectIdModulesModuleIdCancelPostRequest.model';
export * from '../models/ProjectsProjectIdModulesModuleIdRunPostRequest.model';
export * from '../models/ProjectsProjectIdModulesPostRequest.model';
Expand Down
Loading
Loading