Skip to content
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
227 changes: 227 additions & 0 deletions apps/api/openapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,26 @@
],
"type": "object"
},
"DeploymentDependency": {
"properties": {
"dependencyDeploymentId": {
"type": "string"
},
"deploymentId": {
"type": "string"
},
"versionSelector": {
"description": "CEL expression evaluated against the dependency deployment's current release version on the same resource.",
"type": "string"
}
},
"required": [
"deploymentId",
"dependencyDeploymentId",
"versionSelector"
],
"type": "object"
},
"DeploymentDependencyRule": {
"properties": {
"dependsOn": {
Expand Down Expand Up @@ -2578,6 +2598,18 @@
},
"type": "object"
},
"UpsertDeploymentDependencyRequest": {
"properties": {
"versionSelector": {
"description": "CEL expression evaluated against the dependency deployment's current release version on the same resource.",
"type": "string"
}
},
"required": [
"versionSelector"
],
"type": "object"
},
"UpsertDeploymentRequest": {
"properties": {
"description": {
Expand Down Expand Up @@ -4805,6 +4837,201 @@
"summary": "Upsert deployment"
}
},
"/v1/workspaces/{workspaceId}/deployments/{deploymentId}/dependencies": {
"get": {
"description": "Returns the dependency edges declared by this deployment.",
"operationId": "listDeploymentDependencies",
"parameters": [
{
"description": "ID of the workspace",
"in": "path",
"name": "workspaceId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "ID of the deployment",
"in": "path",
"name": "deploymentId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/DeploymentDependency"
},
"type": "array"
}
}
},
"description": "OK response"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Resource not found"
}
},
"summary": "List deployment dependencies"
}
},
"/v1/workspaces/{workspaceId}/deployments/{deploymentId}/dependencies/{dependencyDeploymentId}": {
"delete": {
"operationId": "requestDeploymentDependencyDeletion",
"parameters": [
{
"description": "ID of the workspace",
"in": "path",
"name": "workspaceId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "ID of the deployment",
"in": "path",
"name": "deploymentId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "ID of the dependency deployment",
"in": "path",
"name": "dependencyDeploymentId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"202": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeploymentRequestAccepted"
}
}
},
"description": "Accepted response"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Invalid request"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Resource not found"
}
},
"summary": "Delete deployment dependency"
},
"put": {
"description": "Declare or update a version-selector dependency from this deployment to another deployment. Identified by the (deploymentId, dependencyDeploymentId) pair.",
"operationId": "requestDeploymentDependencyUpsert",
Comment on lines +4959 to +4960
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.

⚠️ Potential issue | 🟠 Major

Edge identity in the API contract does not match the stated requirement.

Line 4949 identifies dependencies by (deploymentId, dependencyDeploymentId), but the requirement defines an edge by (deploymentId, dependencyDeploymentId, versionSelector). This contract cannot uniquely update/delete multiple selectors for the same deployment pair. Please align mutation identity with the required tuple (or explicitly redefine uniqueness as pair everywhere).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/openapi/openapi.json` around lines 4949 - 4950, The OpenAPI contract
currently identifies dependency mutations by the pair (deploymentId,
dependencyDeploymentId) but the requirement says the edge is (deploymentId,
dependencyDeploymentId, versionSelector); update the operation and relevant
schemas so identity includes versionSelector: modify operationId
requestDeploymentDependencyUpsert and its description to state the tuple
includes versionSelector, add versionSelector as a required parameter (or part
of the request body) to the upsert and delete operations, and update any
request/response schemas (e.g., the dependency resource/identifier object) so
uniqueness and ID fields reflect (deploymentId, dependencyDeploymentId,
versionSelector).

"parameters": [
{
"description": "ID of the workspace",
"in": "path",
"name": "workspaceId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "ID of the deployment",
"in": "path",
"name": "deploymentId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "ID of the dependency deployment",
"in": "path",
"name": "dependencyDeploymentId",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpsertDeploymentDependencyRequest"
}
}
},
"required": true
},
"responses": {
"202": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeploymentRequestAccepted"
}
}
},
"description": "Accepted response"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Invalid request"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "Resource not found"
}
},
"summary": "Upsert deployment dependency"
}
},
"/v1/workspaces/{workspaceId}/deployments/{deploymentId}/plan": {
"post": {
"description": "Compute a dry-run plan showing rendered diffs for each release target without creating a version.",
Expand Down
51 changes: 51 additions & 0 deletions apps/api/openapi/paths/deployments.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,57 @@ local openapi = import '../lib/openapi.libsonnet';
+ openapi.badRequestResponse(),
},
},
'/v1/workspaces/{workspaceId}/deployments/{deploymentId}/dependencies': {
get: {
summary: 'List deployment dependencies',
description: "Returns the dependency edges declared by this deployment.",
operationId: 'listDeploymentDependencies',
parameters: [
openapi.workspaceIdParam(),
openapi.deploymentIdParam(),
],
responses: openapi.okResponse({
type: 'array',
items: openapi.schemaRef('DeploymentDependency'),
})
+ openapi.notFoundResponse(),
},
},
'/v1/workspaces/{workspaceId}/deployments/{deploymentId}/dependencies/{dependencyDeploymentId}': {
put: {
summary: 'Upsert deployment dependency',
description: 'Declare or update a version-selector dependency from this deployment to another deployment. Identified by the (deploymentId, dependencyDeploymentId) pair.',
operationId: 'requestDeploymentDependencyUpsert',
parameters: [
openapi.workspaceIdParam(),
openapi.deploymentIdParam(),
openapi.stringParam('dependencyDeploymentId', 'ID of the dependency deployment'),
],
requestBody: {
required: true,
content: {
'application/json': {
schema: openapi.schemaRef('UpsertDeploymentDependencyRequest'),
},
},
},
responses: openapi.acceptedResponse(openapi.schemaRef('DeploymentRequestAccepted'))
+ openapi.notFoundResponse()
+ openapi.badRequestResponse(),
},
delete: {
summary: 'Delete deployment dependency',
operationId: 'requestDeploymentDependencyDeletion',
parameters: [
openapi.workspaceIdParam(),
openapi.deploymentIdParam(),
openapi.stringParam('dependencyDeploymentId', 'ID of the dependency deployment'),
],
responses: openapi.acceptedResponse(openapi.schemaRef('DeploymentRequestAccepted'))
+ openapi.notFoundResponse()
+ openapi.badRequestResponse(),
},
},
'/v1/workspaces/{workspaceId}/deployments/{deploymentId}/plan': {
post: {
summary: 'Create a deployment plan',
Expand Down
24 changes: 24 additions & 0 deletions apps/api/openapi/schemas/deployments.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,30 @@ local jobAgentConfig = {
},
},

UpsertDeploymentDependencyRequest: {
type: 'object',
required: ['versionSelector'],
properties: {
versionSelector: {
type: 'string',
description: "CEL expression evaluated against the dependency deployment's current release version on the same resource.",
},
},
},

DeploymentDependency: {
type: 'object',
required: ['deploymentId', 'dependencyDeploymentId', 'versionSelector'],
properties: {
deploymentId: { type: 'string' },
dependencyDeploymentId: { type: 'string' },
versionSelector: {
type: 'string',
description: "CEL expression evaluated against the dependency deployment's current release version on the same resource.",
},
},
},

DeploymentRequestAccepted: {
type: 'object',
required: ['id', 'message'],
Expand Down
Loading
Loading