Skip to content

feat(x2a): Initial API changes for devspaces#2594

Open
eloycoto wants to merge 1 commit intoredhat-developer:mainfrom
eloycoto:AnsibleDevSpaces
Open

feat(x2a): Initial API changes for devspaces#2594
eloycoto wants to merge 1 commit intoredhat-developer:mainfrom
eloycoto:AnsibleDevSpaces

Conversation

@eloycoto
Copy link
Copy Markdown
Contributor

@eloycoto eloycoto commented Mar 24, 2026

To enable Openshift dev spaces we need a way to:

Trigger: Post the devspace.
URL: Get the devspace for a project
Delete: Delete the devspace when the user finished.

This is just the placeholder for the API, because I expect hard opinions on this topic, so just the placeholder for the API, and a followup of 6 to 10 PR step by step, from the deployment to the bussiness logic in backstage.

Second PR for FLPATH-3457
Related PR: x2ansible/x2a-convertor#156

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app bot commented Mar 24, 2026

Missing Changesets

The following package(s) are changed by this PR but do not have a changeset:

  • @red-hat-developer-hub/backstage-plugin-x2a-backend
  • @red-hat-developer-hub/backstage-plugin-x2a-common

See CONTRIBUTING.md for more information about how to add changesets.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-x2a-backend workspaces/x2a/plugins/x2a-backend none v1.0.2
@red-hat-developer-hub/backstage-plugin-x2a-common workspaces/x2a/plugins/x2a-common none v1.0.2

@rhdh-qodo-merge
Copy link
Copy Markdown

Review Summary by Qodo

Add OpenShift Dev Spaces API endpoints for Ansible development workspaces

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add OpenShift Dev Spaces API endpoints for workspace management
• Implement GET, POST, DELETE operations on /projects/{projectId}/devspaces
• Define DevSpacesWorkspace model with status tracking and metadata
• Generate TypeScript types and client methods for both backend and frontend
Diagram
flowchart LR
  A["API Specification<br/>openapi.yaml"] -->|"generates"| B["Backend Types<br/>Api.server.ts"]
  A -->|"generates"| C["Frontend Client<br/>Api.client.ts"]
  B -->|"imports"| D["DevSpacesWorkspace<br/>Models"]
  C -->|"imports"| D
  D -->|"includes"| E["Status Enum<br/>starting/running/stopped/failed"]
  B -->|"defines"| F["Endpoints<br/>GET/POST/DELETE"]
  C -->|"provides"| G["Client Methods<br/>projectsProjectIdDevspaces*"]
Loading

Grey Divider

File Changes

1. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/apis/Api.server.ts ✨ Enhancement +40/-0

Add DevSpaces endpoint type definitions for server

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/apis/Api.server.ts


2. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/DevSpacesWorkspace.model.ts ✨ Enhancement +43/-0

Define DevSpacesWorkspace interface with metadata

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/DevSpacesWorkspace.model.ts


3. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/DevSpacesWorkspaceStatus.model.ts ✨ Enhancement +28/-0

Define workspace status enum type

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/DevSpacesWorkspaceStatus.model.ts


View more (13)
4. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesDelete200Response.model.ts ✨ Enhancement +33/-0

Define delete response model with confirmation

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesDelete200Response.model.ts


5. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesPost201Response.model.ts ✨ Enhancement +35/-0

Define creation response model with workspace ID

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesPost201Response.model.ts


6. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/index.ts ✨ Enhancement +4/-0

Export new DevSpaces model types

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/models/index.ts


7. workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/router.ts ✨ Enhancement +176/-0

Add OpenAPI spec for DevSpaces endpoints

workspaces/x2a/plugins/x2a-backend/src/schema/openapi/generated/router.ts


8. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/apis/Api.client.ts ✨ Enhancement +112/-0

Add DevSpaces client methods and type definitions

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/apis/Api.client.ts


9. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/DevSpacesWorkspace.model.ts ✨ Enhancement +43/-0

Define DevSpacesWorkspace interface for client

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/DevSpacesWorkspace.model.ts


10. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/DevSpacesWorkspaceStatus.model.ts ✨ Enhancement +28/-0

Define workspace status enum for client

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/DevSpacesWorkspaceStatus.model.ts


11. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesDelete200Response.model.ts ✨ Enhancement +33/-0

Define delete response model for client

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesDelete200Response.model.ts


12. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesPost201Response.model.ts ✨ Enhancement +35/-0

Define creation response model for client

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/ProjectsProjectIdDevspacesPost201Response.model.ts


13. workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/index.ts ✨ Enhancement +4/-0

Export DevSpaces models from client package

workspaces/x2a/plugins/x2a-common/client/src/schema/openapi/generated/models/index.ts


14. workspaces/x2a/plugins/x2a-backend/src/schema/openapi.yaml 📝 Documentation +139/-0

Add DevSpaces endpoint specifications to OpenAPI

workspaces/x2a/plugins/x2a-backend/src/schema/openapi.yaml


15. workspaces/x2a/plugins/x2a-common/report.api.md 📝 Documentation +51/-0

Update API report with DevSpaces types

workspaces/x2a/plugins/x2a-common/report.api.md


16. workspaces/x2a/plugins/x2a/report.api.md Miscellaneous +3/-3

Update import paths for translation references

workspaces/x2a/plugins/x2a/report.api.md


Grey Divider

Qodo Logo

@rhdh-qodo-merge
Copy link
Copy Markdown

rhdh-qodo-merge bot commented Mar 24, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Devspaces endpoints unimplemented 🐞 Bug ✓ Correctness
Description
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.
Code

workspaces/x2a/plugins/x2a-backend/src/schema/openapi.yaml[R535-636]

+  /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
+
Evidence
The OpenAPI spec now includes the DevSpaces endpoints, and the generated API types include these
routes, which will encourage usage. However, the backend router only registers project/module/job
routes and the project routes file does not define any /devspaces routes, so there is no code path
to handle these requests.

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/generated/apis/Api.server.ts[94-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### 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


2. Missing runtime type dependency 🐞 Bug ⛯ Reliability
Description
The x2a package public API now imports TranslationRef/TranslationResource from
@backstage/frontend-plugin-api, but that package is only listed under devDependencies, which can
break downstream TypeScript builds consuming the published types.
Code

workspaces/x2a/plugins/x2a/report.api.md[R12-13]

+import { TranslationRef } from '@backstage/frontend-plugin-api';
+import { TranslationResource } from '@backstage/frontend-plugin-api';
Evidence
API Extractor’s report reflects the package’s public type surface; when it references types from
@backstage/frontend-plugin-api, consumers need that package resolvable at compile time. In this
repo, @backstage/frontend-plugin-api is only in devDependencies for the x2a package, which is not
guaranteed to be installed for consumers of the published package.

workspaces/x2a/plugins/x2a/report.api.md[7-14]
workspaces/x2a/plugins/x2a/package.json[37-74]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`@backstage/frontend-plugin-api` appears in the published API surface (via the API report / emitted d.ts), but it is only declared as a devDependency. This can cause downstream TypeScript resolution failures.

### Issue Context
The API report includes:
- `TranslationRef` from `@backstage/frontend-plugin-api`
- `TranslationResource` from `@backstage/frontend-plugin-api`

### Fix Focus Areas
- Move `@backstage/frontend-plugin-api` from `devDependencies` to `dependencies` (or `peerDependencies` if that matches your packaging policy), ensuring consumers can resolve the types.

- workspaces/x2a/plugins/x2a/package.json[37-74]
- workspaces/x2a/plugins/x2a/report.api.md[7-14]

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +535 to +636
/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

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

Comment on lines +12 to +13
import { TranslationRef } from '@backstage/frontend-plugin-api';
import { TranslationResource } from '@backstage/frontend-plugin-api';
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

2. Missing runtime type dependency 🐞 Bug ⛯ Reliability

The x2a package public API now imports TranslationRef/TranslationResource from
@backstage/frontend-plugin-api, but that package is only listed under devDependencies, which can
break downstream TypeScript builds consuming the published types.
Agent Prompt
### Issue description
`@backstage/frontend-plugin-api` appears in the published API surface (via the API report / emitted d.ts), but it is only declared as a devDependency. This can cause downstream TypeScript resolution failures.

### Issue Context
The API report includes:
- `TranslationRef` from `@backstage/frontend-plugin-api`
- `TranslationResource` from `@backstage/frontend-plugin-api`

### Fix Focus Areas
- Move `@backstage/frontend-plugin-api` from `devDependencies` to `dependencies` (or `peerDependencies` if that matches your packaging policy), ensuring consumers can resolve the types.

- workspaces/x2a/plugins/x2a/package.json[37-74]
- workspaces/x2a/plugins/x2a/report.api.md[7-14]

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

Copy link
Copy Markdown
Contributor

@elai-shalev elai-shalev left a comment

Choose a reason for hiding this comment

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

overall looks good. assuming its a contract api pr for now

Comment on lines +119 to +120
| void
| void;
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.

Comment on lines +930 to +931
"required": [
"message"
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.

maybe add deletedWorkspaceId to the required?

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.

you might add two times the DELETE request, and there is no workspace, so cannot be required because does not exist yet.

To enable Openshift dev spaces we need a way to:

Trigger: Post the devspace.
URL: Get the devspace for a project
Delete: Delete the devspace when the user finished.

This is just the placeholder for the API, because I expect hard opinions on this topic, so just the placeholder for the API, and a followup of 6 to 10 PR step by step, from the deployment to the bussiness logic in backstage.

Signed-off-by: Eloy Coto <eloy.coto@acalustra.com>
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Member

@mareklibra mareklibra left a comment

Choose a reason for hiding this comment

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

It would make more sense to merge this along particular endpoint implementation to avoid orphaned code in the tree. But since there is a clear path to do it asap, it's ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants