mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: a failed anchor read is not a raced deploy, and take latest closes only its own drawer
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2d0a4f777f
commit
1662dfbc33
@@ -198,9 +198,13 @@
|
||||
async function takeLatest() {
|
||||
if (!data || data.mode !== 'normal' || !data.onTakeLatest || takingLatest) return
|
||||
takingLatest = true
|
||||
// Persisting the base is awaited, and this drawer outlives the editor that filled
|
||||
// it: close only the opening this action belongs to, or it takes down whichever
|
||||
// diff was opened meanwhile.
|
||||
const opening = openingToken
|
||||
try {
|
||||
await data.onTakeLatest(headShown)
|
||||
diffViewer?.closeDrawer()
|
||||
if (opening === openingToken) diffViewer?.closeDrawer()
|
||||
} finally {
|
||||
takingLatest = false
|
||||
}
|
||||
|
||||
@@ -369,10 +369,12 @@
|
||||
policy = await updatePolicy($app, policy)
|
||||
// Read the head this deploy is about to append to, so the entry it writes can be
|
||||
// told from one landing beside it (see versionThisDeployWrote).
|
||||
const headBefore = await AppService.getAppLatestVersion({
|
||||
workspace: $workspaceStore!,
|
||||
path: $appPath
|
||||
}).catch(() => undefined)
|
||||
const anchor = (
|
||||
await AppService.getAppLatestVersion({
|
||||
workspace: $workspaceStore!,
|
||||
path: $appPath
|
||||
}).catch(() => undefined)
|
||||
)?.version
|
||||
await AppService.updateApp({
|
||||
workspace: $workspaceStore!,
|
||||
path: $appPath!,
|
||||
@@ -405,11 +407,13 @@
|
||||
})
|
||||
// `version` is what is deployed now, which is the deploy guard's fallback head and
|
||||
// must stay set; `claimed` is the version this deploy can prove it wrote.
|
||||
const claimed = versionThisDeployWrote(appHistory, $userStore?.username, headBefore?.version)
|
||||
const claimed = versionThisDeployWrote(appHistory, $userStore?.username, anchor)
|
||||
version = appHistory[0]?.version
|
||||
// Without a claim the head is someone else's as far as this editor knows, so it is
|
||||
// no longer a base it may compare against: `compareVersions` confirms instead.
|
||||
baseUnknown = claimed === undefined
|
||||
// A deploy landed beside this one, so the head is someone else's as far as this
|
||||
// editor knows and is no longer a base it may compare against: `compareVersions`
|
||||
// confirms instead. A failed anchor read claims nothing either, but it is no
|
||||
// evidence of that, so it does not arm this.
|
||||
baseUnknown = claimed === undefined && anchor != null
|
||||
// Re-pin the fork base to the version just written: the editor stays open, so a
|
||||
// follow-up deploy (or a new edit) would otherwise compare against the now-
|
||||
// superseded base and falsely warn. parent_version is in
|
||||
|
||||
@@ -7,6 +7,9 @@ export function computeSecretUrl(secretUrl: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared by both app editors: classic and raw apps deploy into the same `app_version`
|
||||
* table and read the same history, so the rule for claiming a version lives here once.
|
||||
*
|
||||
* The version a just-finished deploy wrote: this caller's newest entry, and only while it
|
||||
* sits directly on `headBefore`, the head read just before the write. That is what the
|
||||
* write appended, so anything else in between belongs to a deploy this cannot tell from
|
||||
|
||||
@@ -98,10 +98,10 @@
|
||||
// staleness outright.
|
||||
const useVersion = $derived(draftBaseVersion != null && deployedHeadVersion != null)
|
||||
const isStale = $derived(
|
||||
// Both paths need a draft to be out of date: the editors clear `draftSavedAt`
|
||||
// when a deploy consumes theirs, and the version pair stays armed for the draft
|
||||
// the next edit starts, which is what the prompt would otherwise offer to
|
||||
// discard seconds after a successful deploy.
|
||||
// Both paths need a draft to be out of date: the app editors stay open across a
|
||||
// deploy and clear `draftSavedAt` when it consumes theirs, while the version pair
|
||||
// stays armed for the draft the next edit starts, which is what the prompt would
|
||||
// otherwise offer to discard seconds after a successful deploy.
|
||||
!!onLoadLatestDeploy &&
|
||||
!!draftSavedAt &&
|
||||
(useVersion
|
||||
|
||||
@@ -521,10 +521,12 @@
|
||||
}
|
||||
// Read the head this deploy is about to append to, so the entry it writes can be
|
||||
// told from one landing beside it (see versionThisDeployWrote).
|
||||
const headBefore = await AppService.getAppLatestVersion({
|
||||
workspace: opWorkspace!,
|
||||
path: appPath!
|
||||
}).catch(() => undefined)
|
||||
const anchor = (
|
||||
await AppService.getAppLatestVersion({
|
||||
workspace: opWorkspace!,
|
||||
path: appPath!
|
||||
}).catch(() => undefined)
|
||||
)?.version
|
||||
await AppService.updateAppRaw({
|
||||
workspace: opWorkspace!,
|
||||
path: appPath!,
|
||||
@@ -563,11 +565,13 @@
|
||||
// draft's base; the head is what is deployed now. The route owns this `version`
|
||||
// prop and re-pushes `parentVersion ?? head` as soon as `onDeploy` returns, so the
|
||||
// guard compares the claimed base when there is one and the head otherwise.
|
||||
const claimed = versionThisDeployWrote(appHistory, $userStore?.username, headBefore?.version)
|
||||
const claimed = versionThisDeployWrote(appHistory, $userStore?.username, anchor)
|
||||
version = appHistory[0]?.version
|
||||
// Without a claim the head is someone else's as far as this editor knows, so it is
|
||||
// no longer a base it may compare against: `compareVersions` confirms instead.
|
||||
baseUnknown = claimed === undefined
|
||||
// A deploy landed beside this one, so the head is someone else's as far as this
|
||||
// editor knows and is no longer a base it may compare against: `compareVersions`
|
||||
// confirms instead. A failed anchor read claims nothing either, but it is no
|
||||
// evidence of that, so it does not arm this.
|
||||
baseUnknown = claimed === undefined && anchor != null
|
||||
|
||||
closeSaveDrawer()
|
||||
sendUserToast('App deployed successfully')
|
||||
|
||||
Reference in New Issue
Block a user