-
Notifications
You must be signed in to change notification settings - Fork 18
chore: wire together deployment planning #953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -565,32 +565,61 @@ | |
| }, | ||
| "DeploymentPlanTarget": { | ||
| "properties": { | ||
| "contentHash": { | ||
| "description": "Hash of the rendered output for change detection", | ||
| "environmentId": { | ||
| "type": "string" | ||
| }, | ||
| "current": { | ||
| "description": "Full rendered output of the currently deployed state", | ||
| "environmentName": { | ||
| "type": "string" | ||
| }, | ||
| "environmentId": { | ||
| "hasChanges": { | ||
| "description": "True if any result for this target has changes", | ||
| "type": "boolean" | ||
| }, | ||
| "resourceId": { | ||
| "type": "string" | ||
| }, | ||
| "environmentName": { | ||
| "resourceName": { | ||
| "type": "string" | ||
| }, | ||
| "results": { | ||
| "items": { | ||
| "$ref": "#/components/schemas/DeploymentPlanTargetResult" | ||
| }, | ||
| "type": "array" | ||
| } | ||
| }, | ||
| "required": [ | ||
| "environmentId", | ||
| "environmentName", | ||
| "resourceId", | ||
| "resourceName", | ||
| "hasChanges", | ||
| "results" | ||
|
Comment on lines
+574
to
+597
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep state-dependent plan fields nullable/variant by
Prefer either:
Also applies to: 603-623, 635-642 🤖 Prompt for AI Agents |
||
| ], | ||
| "type": "object" | ||
| }, | ||
| "DeploymentPlanTargetResult": { | ||
| "properties": { | ||
| "contentHash": { | ||
| "description": "Hash of the rendered output for change detection", | ||
| "type": "string" | ||
| }, | ||
| "current": { | ||
| "description": "Full rendered output of the currently deployed state", | ||
| "type": "string" | ||
| }, | ||
| "hasChanges": { | ||
| "nullable": true, | ||
| "type": "boolean" | ||
| }, | ||
| "proposed": { | ||
| "description": "Full rendered output of the proposed version", | ||
| "id": { | ||
| "type": "string" | ||
| }, | ||
| "resourceId": { | ||
| "message": { | ||
| "description": "Agent message (e.g. error explanation or summary)", | ||
| "type": "string" | ||
| }, | ||
| "resourceName": { | ||
| "proposed": { | ||
| "description": "Full rendered output of the proposed version", | ||
| "type": "string" | ||
| }, | ||
| "status": { | ||
|
|
@@ -604,11 +633,13 @@ | |
| } | ||
| }, | ||
| "required": [ | ||
| "environmentId", | ||
| "environmentName", | ||
| "resourceId", | ||
| "resourceName", | ||
| "status" | ||
| "id", | ||
| "status", | ||
| "hasChanges", | ||
| "contentHash", | ||
| "current", | ||
| "proposed", | ||
| "message" | ||
| ], | ||
| "type": "object" | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -396,7 +396,7 @@ const createDeploymentPlan: AsyncTypedHandler< | |||||||||||||||||||||
| res.status(202).json({ | ||||||||||||||||||||||
| id: planId, | ||||||||||||||||||||||
| status: "computing", | ||||||||||||||||||||||
| summary: null, | ||||||||||||||||||||||
| summary: { total: 0, changed: 0, unchanged: 0, errored: 0, unsupported: 0 }, | ||||||||||||||||||||||
| targets: [], | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
@@ -437,11 +437,11 @@ const getDeploymentPlan: AsyncTypedHandler< | |||||||||||||||||||||
| results: t.results.map((r) => ({ | ||||||||||||||||||||||
| id: r.id, | ||||||||||||||||||||||
| status: r.status, | ||||||||||||||||||||||
| hasChanges: r.hasChanges, | ||||||||||||||||||||||
| current: r.current, | ||||||||||||||||||||||
| proposed: r.proposed, | ||||||||||||||||||||||
| contentHash: r.contentHash, | ||||||||||||||||||||||
| message: r.message, | ||||||||||||||||||||||
| hasChanges: r.hasChanges ?? false, | ||||||||||||||||||||||
| contentHash: r.contentHash ?? "", | ||||||||||||||||||||||
| current: r.current ?? "", | ||||||||||||||||||||||
| proposed: r.proposed ?? "", | ||||||||||||||||||||||
| message: r.message ?? "", | ||||||||||||||||||||||
|
Comment on lines
+440
to
+444
|
||||||||||||||||||||||
| hasChanges: r.hasChanges ?? false, | |
| contentHash: r.contentHash ?? "", | |
| current: r.current ?? "", | |
| proposed: r.proposed ?? "", | |
| message: r.message ?? "", | |
| hasChanges: r.hasChanges ?? undefined, | |
| contentHash: r.contentHash ?? undefined, | |
| current: r.current ?? undefined, | |
| proposed: r.proposed ?? undefined, | |
| message: r.message ?? undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t serialize unknown result state as concrete values.
For rows that are still computing, hasChanges is still unknown in the database. Converting that to false here makes pending results look unchanged, while summary is still derived from the raw nullable value. contentHash/current/proposed/message have the same problem: "" is no longer distinguishable from “not produced yet”. Preserve undefined until those fields are actually populated, or compute the summary from the same normalized object.
Possible fix
results: t.results.map((r) => ({
id: r.id,
status: r.status,
- hasChanges: r.hasChanges ?? false,
- contentHash: r.contentHash ?? "",
- current: r.current ?? "",
- proposed: r.proposed ?? "",
- message: r.message ?? "",
+ hasChanges: r.hasChanges ?? undefined,
+ contentHash: r.contentHash ?? undefined,
+ current: r.current ?? undefined,
+ proposed: r.proposed ?? undefined,
+ message: r.message ?? undefined,
})),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/src/routes/v1/workspaces/deployments.ts` around lines 437 - 445, The
map that builds the serialized result objects (the results: t.results.map block)
currently forces nullable fields to concrete values (hasChanges => false,
contentHash/current/proposed/message => ""), which hides "not yet produced"
state for rows still computing; change the mapper to preserve undefined for
those fields (omit the null-coalescing defaults) so hasChanges stays undefined
when DB value is null, and likewise leave contentHash, current, proposed,
message as undefined until populated, or alternatively compute the derived
summary from the same normalized object so both summary and exported fields
reflect the same nullable/undefined semantics; update the results mapping code
(the mapper that returns id, status, hasChanges, contentHash, current, proposed,
message) accordingly.
Uh oh!
There was an error while loading. Please reload this page.