mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-29 08:12:56 +00:00
Merge remote-tracking branch 'origin/main' into datatable-perms-3
# Conflicts: # backend/ee-repo-ref.txt
This commit is contained in:
@@ -191,7 +191,14 @@ function createSveltePlugin(appDir: string): any {
|
||||
|
||||
// Convert Svelte syntax to JavaScript
|
||||
try {
|
||||
const { js, warnings } = svelte.compile(source, { filename });
|
||||
// The raw-app editor's in-browser bundler compiles with
|
||||
// `css: "injected"`, so this must too, or the same app renders
|
||||
// styled there and unstyled once the CLI builds it: Svelte's default
|
||||
// ("external") hands the <style> back on a `css` field nothing emits.
|
||||
const { js, warnings } = svelte.compile(source, {
|
||||
filename,
|
||||
css: "injected",
|
||||
});
|
||||
const contents = js.code + `//# sourceMappingURL=` + js.map.toUrl();
|
||||
return { contents, warnings: warnings.map(convertMessage) };
|
||||
} catch (e: any) {
|
||||
|
||||
+108
-44
@@ -26,37 +26,33 @@ async function readDirRecursive(
|
||||
return out;
|
||||
}
|
||||
|
||||
/** The workspace's shared UI store, or undefined when it cannot be read. */
|
||||
async function fetchSharedUi(
|
||||
workspace: string,
|
||||
): Promise<Record<string, string> | undefined> {
|
||||
try {
|
||||
const got = await wmill.getSharedUi({ workspace });
|
||||
return got.files ?? {};
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export type SharedUiChange =
|
||||
| { type: "added"; path: string }
|
||||
| { type: "edited"; path: string; before: string; after: string }
|
||||
| { type: "deleted"; path: string };
|
||||
|
||||
/**
|
||||
* Diff the local <cwd>/ui/ folder against the workspace's shared UI store in
|
||||
* the push direction (local -> remote), returning entries whose `path` is
|
||||
* prefixed with `ui/`. This is the same comparison pushSharedUi applies, so the
|
||||
* dry-run preview and the real push never diverge.
|
||||
*
|
||||
* Mirrors pushSharedUi's no-op: with no local ui/ folder there is nothing to
|
||||
* push, so the apply is a no-op and the preview must be empty (even when the
|
||||
* remote store is non-empty) to avoid phantom diffs the apply won't perform.
|
||||
* The push-direction diff (local -> remote) of two already-read file maps.
|
||||
* Split out so the preview and the push itself compare identically off one
|
||||
* read of each side.
|
||||
*/
|
||||
export async function diffSharedUi(workspace: string): Promise<SharedUiChange[]> {
|
||||
const localDir = path.join(process.cwd(), SHARED_UI_DIR);
|
||||
if (!fs.existsSync(localDir)) {
|
||||
return [];
|
||||
}
|
||||
const files = await readDirRecursive(localDir);
|
||||
|
||||
let remote: Record<string, string> = {};
|
||||
try {
|
||||
const got = await wmill.getSharedUi({ workspace });
|
||||
remote = got.files ?? {};
|
||||
} catch {
|
||||
// If endpoint missing or unauthorized, treat remote as empty (the push
|
||||
// would attempt the PUT anyway).
|
||||
}
|
||||
|
||||
function sharedUiChanges(
|
||||
files: Record<string, string>,
|
||||
remote: Record<string, string>,
|
||||
keepDeleted?: boolean,
|
||||
): SharedUiChange[] {
|
||||
// Use Object.hasOwn, not `in`: a file named after an Object.prototype member
|
||||
// (e.g. ui/toString) would otherwise register as always-present and be
|
||||
// misdiffed.
|
||||
@@ -69,34 +65,97 @@ export async function diffSharedUi(workspace: string): Promise<SharedUiChange[]>
|
||||
changes.push({ type: "edited", path: p, before: remote[rel], after: content });
|
||||
}
|
||||
}
|
||||
for (const rel of Object.keys(remote)) {
|
||||
if (!Object.hasOwn(files, rel)) {
|
||||
changes.push({ type: "deleted", path: `${SHARED_UI_DIR}/${rel}` });
|
||||
if (!keepDeleted) {
|
||||
for (const rel of Object.keys(remote)) {
|
||||
if (!Object.hasOwn(files, rel)) {
|
||||
changes.push({ type: "deleted", path: `${SHARED_UI_DIR}/${rel}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff the local <cwd>/ui/ folder against the workspace's shared UI store in
|
||||
* the push direction (local -> remote), returning entries whose `path` is
|
||||
* prefixed with `ui/`. This is the same comparison pushSharedUi applies, so the
|
||||
* dry-run preview and the real push never diverge.
|
||||
*
|
||||
* Mirrors pushSharedUi's no-ops: with no local ui/ folder, or under
|
||||
* `keepDeleted` with an unreadable store, the apply does nothing, so the
|
||||
* preview must be empty (even when the remote store is non-empty) to avoid
|
||||
* phantom diffs the apply won't perform.
|
||||
*/
|
||||
export async function diffSharedUi(
|
||||
workspace: string,
|
||||
keepDeleted?: boolean,
|
||||
): Promise<SharedUiChange[]> {
|
||||
const localDir = path.join(process.cwd(), SHARED_UI_DIR);
|
||||
if (!fs.existsSync(localDir)) {
|
||||
return [];
|
||||
}
|
||||
const files = await readDirRecursive(localDir);
|
||||
const remote = await fetchSharedUi(workspace);
|
||||
if (remote === undefined && keepDeleted) {
|
||||
return [];
|
||||
}
|
||||
// If endpoint missing or unauthorized, treat remote as empty (the push
|
||||
// would attempt the PUT anyway).
|
||||
return sharedUiChanges(files, remote ?? {}, keepDeleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the local <cwd>/ui/ folder to the workspace's shared UI store.
|
||||
* Returns true if a push was performed, false if the folder is missing or
|
||||
* already matches the remote store. Note an empty-but-existing folder still
|
||||
* pushes an empty map (clearing the remote store) if the remote is non-empty.
|
||||
* pushes an empty map (clearing the remote store) if the remote is non-empty —
|
||||
* unless `keepDeleted`, which folds remote-only files back into the map.
|
||||
*/
|
||||
export async function pushSharedUi(workspace: string): Promise<boolean> {
|
||||
export async function pushSharedUi(
|
||||
workspace: string,
|
||||
keepDeleted?: boolean,
|
||||
): Promise<boolean> {
|
||||
const localDir = path.join(process.cwd(), SHARED_UI_DIR);
|
||||
if (!fs.existsSync(localDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip if no change — reuse diffSharedUi so preview and push never diverge.
|
||||
const diff = await diffSharedUi(workspace);
|
||||
if (diff.length === 0) {
|
||||
const files = await readDirRecursive(localDir);
|
||||
const remote = await fetchSharedUi(workspace);
|
||||
// The store is written whole, so a remote-only file is pruned by omission
|
||||
// alone. An unreadable store leaves no way to carry those files over, so
|
||||
// the shared UI is left untouched rather than cleared.
|
||||
if (remote === undefined && keepDeleted) {
|
||||
log.warn(
|
||||
colors.yellow(
|
||||
"Could not read the shared UI folder from the remote; skipping its push so --keep-deleted does not clear it.",
|
||||
),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Same comparison as diffSharedUi, off the same two maps, so preview and
|
||||
// push never diverge.
|
||||
if (sharedUiChanges(files, remote ?? {}, keepDeleted).length === 0) {
|
||||
log.info(colors.gray("Shared UI folder up to date"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const files = await readDirRecursive(localDir);
|
||||
if (keepDeleted) {
|
||||
for (const [rel, content] of Object.entries(remote!)) {
|
||||
// defineProperty, not assignment: `files.__proto__ = "..."` runs the
|
||||
// inherited setter and creates no own property, so a remote `ui/__proto__`
|
||||
// would be dropped from the whole-map PUT — i.e. deleted despite the flag.
|
||||
if (!Object.hasOwn(files, rel)) {
|
||||
Object.defineProperty(files, rel, {
|
||||
value: content,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
await wmill.updateSharedUi({
|
||||
workspace,
|
||||
requestBody: { files },
|
||||
@@ -111,9 +170,12 @@ export async function pushSharedUi(workspace: string): Promise<boolean> {
|
||||
|
||||
/**
|
||||
* Pull the workspace's shared UI store into <cwd>/ui/.
|
||||
* Files removed remotely are also removed locally.
|
||||
* Files removed remotely are also removed locally, unless `keepDeleted`.
|
||||
*/
|
||||
export async function pullSharedUi(workspace: string): Promise<boolean> {
|
||||
export async function pullSharedUi(
|
||||
workspace: string,
|
||||
keepDeleted?: boolean,
|
||||
): Promise<boolean> {
|
||||
const localDir = path.join(process.cwd(), SHARED_UI_DIR);
|
||||
let got;
|
||||
try {
|
||||
@@ -145,15 +207,17 @@ export async function pullSharedUi(workspace: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
// Delete locally-orphaned files
|
||||
const known = new Set(Object.keys(files));
|
||||
const local = await readDirRecursive(localDir);
|
||||
for (const rel of Object.keys(local)) {
|
||||
if (!known.has(rel)) {
|
||||
const full = path.join(localDir, rel);
|
||||
try {
|
||||
fs.unlinkSync(full);
|
||||
} catch {
|
||||
// ignore
|
||||
if (!keepDeleted) {
|
||||
const known = new Set(Object.keys(files));
|
||||
const local = await readDirRecursive(localDir);
|
||||
for (const rel of Object.keys(local)) {
|
||||
if (!known.has(rel)) {
|
||||
const full = path.join(localDir, rel);
|
||||
try {
|
||||
fs.unlinkSync(full);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3174,6 +3174,28 @@ export function untrackedDatatableMigrationDeletions<
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* `--keep-deleted`: strip every deletion from the changeset, in place, so the
|
||||
* sync only adds and updates. A path missing on one side is not on its own
|
||||
* evidence that it should go from the other — a partial clone, a scoped
|
||||
* checkout or an item authored in the UI all read as deletions here.
|
||||
*/
|
||||
function dropDeletions(changes: Change[], keptOn: "local" | "remote"): void {
|
||||
const deletions = changes.filter((c) => c.name === "deleted");
|
||||
if (deletions.length === 0) return;
|
||||
const kept = changes.filter((c) => c.name !== "deleted");
|
||||
changes.length = 0;
|
||||
changes.push(...kept);
|
||||
log.info(
|
||||
colors.yellow(
|
||||
`--keep-deleted: keeping ${deletions.length} item(s) that exist only ` +
|
||||
(keptOn === "local"
|
||||
? `on disk instead of deleting them locally`
|
||||
: `on the remote instead of deleting them from the workspace`),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
interface ChangeTracker {
|
||||
scripts: string[];
|
||||
flows: string[];
|
||||
@@ -3433,6 +3455,7 @@ export async function pull(
|
||||
repository?: string;
|
||||
promotion?: string;
|
||||
branch?: string;
|
||||
keepDeleted?: boolean;
|
||||
useIndividualBranch?: boolean;
|
||||
groupByFolder?: boolean;
|
||||
gitDeployItems?: string;
|
||||
@@ -3684,6 +3707,10 @@ export async function pull(
|
||||
await isCaseInsensitiveFilesystem(process.cwd()),
|
||||
);
|
||||
|
||||
if (opts.keepDeleted) {
|
||||
dropDeletions(changes, "local");
|
||||
}
|
||||
|
||||
log.info(
|
||||
`remote (${workspace.name}) -> local: ${changes.length} changes to apply`,
|
||||
);
|
||||
@@ -4117,10 +4144,14 @@ export async function pull(
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await pullSharedUi(workspace.workspaceId);
|
||||
} catch (e) {
|
||||
log.warn(`Failed to pull shared UI folder: ${e}`);
|
||||
// Skipped under --dry-run since pullSharedUi writes to the local ui/ folder.
|
||||
// An empty changeset falls through the return above and reaches here.
|
||||
if (!opts.dryRun) {
|
||||
try {
|
||||
await pullSharedUi(workspace.workspaceId, opts.keepDeleted);
|
||||
} catch (e) {
|
||||
log.warn(`Failed to pull shared UI folder: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Datatable migrations are part of the workspace export now, so they flow
|
||||
@@ -4425,12 +4456,19 @@ function removeSuffix(str: string, suffix: string) {
|
||||
}
|
||||
|
||||
// Shown after a `wmill sync push --dry-run` preview that has changes. `sync push`
|
||||
// deploys to the remote workspace and is destructive (it overwrites and prunes
|
||||
// remote items that differ from or are absent locally), so the preview reminds
|
||||
// the caller — especially an AI agent that ran the dry-run to inspect changes —
|
||||
// to get explicit user confirmation before applying it for real.
|
||||
const SYNC_PUSH_DESTRUCTIVE_WARNING =
|
||||
"`wmill sync push` is destructive: applying it deploys these changes to the remote workspace and overwrites or deletes remote items that differ from or are absent locally — this is not automatically reversible. If you are an AI agent, do NOT run `wmill sync push` (without --dry-run) until the user has explicitly confirmed this deploy, unless your custom instructions explicitly allow bypassing that confirmation.";
|
||||
// deploys to the remote workspace and is destructive (it overwrites remote items
|
||||
// that differ from local, and prunes those absent locally unless --keep-deleted),
|
||||
// so the preview reminds the caller — especially an AI agent that ran the dry-run
|
||||
// to inspect changes — to get explicit user confirmation before applying it for real.
|
||||
function syncPushDestructiveWarning(keepDeleted?: boolean): string {
|
||||
return (
|
||||
"`wmill sync push` is destructive: applying it deploys these changes to the remote workspace and overwrites " +
|
||||
(keepDeleted
|
||||
? "remote items that differ from local"
|
||||
: "or deletes remote items that differ from or are absent locally") +
|
||||
" — this is not automatically reversible. If you are an AI agent, do NOT run `wmill sync push` (without --dry-run) until the user has explicitly confirmed this deploy, unless your custom instructions explicitly allow bypassing that confirmation."
|
||||
);
|
||||
}
|
||||
|
||||
// A script pushed without a local lock queues a server-side dependency job; if
|
||||
// that job fails the script deploys broken (no lock/assets) with no CLI signal.
|
||||
@@ -4490,6 +4528,7 @@ export async function push(
|
||||
SyncOptions & {
|
||||
repository?: string;
|
||||
branch?: string;
|
||||
keepDeleted?: boolean;
|
||||
acceptOverridingPermissionedAsWithSelf?: boolean;
|
||||
},
|
||||
) {
|
||||
@@ -4791,6 +4830,13 @@ export async function push(
|
||||
);
|
||||
}
|
||||
|
||||
// After the shared-lock pass, which reads a shared lockfile's deletion as the
|
||||
// signal that this checkout is not deduplicated — an advisory about the local
|
||||
// tree that holds whether or not remote items are being kept.
|
||||
if (opts.keepDeleted) {
|
||||
dropDeletions(changes, "remote");
|
||||
}
|
||||
|
||||
const autoRegenerate = !!(opts as any).autoMetadata;
|
||||
const staleScripts: string[] = [];
|
||||
const staleFlows: string[] = [];
|
||||
@@ -5103,7 +5149,10 @@ export async function push(
|
||||
// unchanged (pushSharedUi still runs) and the summary count includes ui/.
|
||||
if (opts.dryRun) {
|
||||
try {
|
||||
for (const c of await diffSharedUi(workspace.workspaceId)) {
|
||||
for (const c of await diffSharedUi(
|
||||
workspace.workspaceId,
|
||||
opts.keepDeleted,
|
||||
)) {
|
||||
if (c.type === "added") {
|
||||
changes.push({ name: "added", path: c.path, content: "" });
|
||||
} else if (c.type === "deleted") {
|
||||
@@ -5275,7 +5324,9 @@ export async function push(
|
||||
: {}),
|
||||
})),
|
||||
total: changes.length,
|
||||
...(changes.length > 0 ? { warning: SYNC_PUSH_DESTRUCTIVE_WARNING } : {}),
|
||||
...(changes.length > 0
|
||||
? { warning: syncPushDestructiveWarning(opts.keepDeleted) }
|
||||
: {}),
|
||||
};
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
return;
|
||||
@@ -5339,7 +5390,9 @@ export async function push(
|
||||
|
||||
if (opts.dryRun) {
|
||||
log.info(colors.gray(`Dry run complete.`));
|
||||
log.warn(colors.yellow(`\n⚠ ${SYNC_PUSH_DESTRUCTIVE_WARNING}`));
|
||||
log.warn(
|
||||
colors.yellow(`\n⚠ ${syncPushDestructiveWarning(opts.keepDeleted)}`),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6313,7 +6366,7 @@ export async function push(
|
||||
}
|
||||
}
|
||||
try {
|
||||
await pushSharedUi(workspace.workspaceId);
|
||||
await pushSharedUi(workspace.workspaceId, opts.keepDeleted);
|
||||
} catch (e) {
|
||||
log.warn(`Failed to push shared UI folder: ${e}`);
|
||||
}
|
||||
@@ -6415,7 +6468,10 @@ export async function push(
|
||||
let sharedUiPushed = false;
|
||||
if (!opts.dryRun) {
|
||||
try {
|
||||
sharedUiPushed = await pushSharedUi(workspace.workspaceId);
|
||||
sharedUiPushed = await pushSharedUi(
|
||||
workspace.workspaceId,
|
||||
opts.keepDeleted,
|
||||
);
|
||||
} catch (e) {
|
||||
log.warn(`Failed to push shared UI folder: ${e}`);
|
||||
}
|
||||
@@ -6480,6 +6536,10 @@ const command = new Command()
|
||||
.option("--include-groups", "Include syncing groups")
|
||||
.option("--include-settings", "Include syncing workspace settings")
|
||||
.option("--include-key", "Include workspace encryption key")
|
||||
.option(
|
||||
"--keep-deleted",
|
||||
"Do not delete local files for items that no longer exist on the remote workspace. Only adds and updates.",
|
||||
)
|
||||
.option("--skip-branch-validation", "Skip git branch validation and prompts")
|
||||
.option("--json-output", "Output results in JSON format")
|
||||
.option(
|
||||
@@ -6543,6 +6603,10 @@ const command = new Command()
|
||||
"--skip-reencrypt-on-key-change",
|
||||
"When the pushed encryption key differs from the remote, do NOT re-encrypt existing remote secrets. Only safe if they are already encrypted with the new key (e.g. workspace/instance migration). Default is to re-encrypt.",
|
||||
)
|
||||
.option(
|
||||
"--keep-deleted",
|
||||
"Do not delete remote items that no longer exist locally. Only adds and updates.",
|
||||
)
|
||||
.option("--skip-branch-validation", "Skip git branch validation and prompts")
|
||||
.option("--json-output", "Output results in JSON format")
|
||||
.option(
|
||||
|
||||
@@ -10,4 +10,4 @@ export const WM_FORK_PREFIX = "wm-fork";
|
||||
// (e.g. utils.ts) can read it without importing main.ts and creating a circular
|
||||
// dependency (main → workspace → utils → main) that triggers a TDZ.
|
||||
// Re-exported from main.ts for backwards compatibility.
|
||||
export const VERSION = "1.796.0";
|
||||
export const VERSION = "1.800.0";
|
||||
|
||||
Generated
+26
-8
@@ -7533,6 +7533,7 @@ sync local with a remote workspaces or the opposite (push or pull)
|
||||
- \`--include-groups\` - Include syncing groups
|
||||
- \`--include-settings\` - Include syncing workspace settings
|
||||
- \`--include-key\` - Include workspace encryption key
|
||||
- \`--keep-deleted\` - Do not delete local files for items that no longer exist on the remote workspace. Only adds and updates.
|
||||
- \`--skip-branch-validation\` - Skip git branch validation and prompts
|
||||
- \`--json-output\` - Output results in JSON format
|
||||
- \`-i --includes <patterns:file[]>\` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes
|
||||
@@ -7564,6 +7565,7 @@ sync local with a remote workspaces or the opposite (push or pull)
|
||||
- \`--include-settings\` - Include syncing workspace settings
|
||||
- \`--include-key\` - Include workspace encryption key
|
||||
- \`--skip-reencrypt-on-key-change\` - When the pushed encryption key differs from the remote, do NOT re-encrypt existing remote secrets. Only safe if they are already encrypted with the new key (e.g. workspace/instance migration). Default is to re-encrypt.
|
||||
- \`--keep-deleted\` - Do not delete remote items that no longer exist locally. Only adds and updates.
|
||||
- \`--skip-branch-validation\` - Skip git branch validation and prompts
|
||||
- \`--json-output\` - Output results in JSON format
|
||||
- \`-i --includes <patterns:file[]>\` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)
|
||||
@@ -7949,7 +7951,9 @@ properties:
|
||||
at once (1-65535)
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -8399,7 +8403,9 @@ properties:
|
||||
as JSON
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -8566,7 +8572,9 @@ properties:
|
||||
endpoint.
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -8690,7 +8698,9 @@ properties:
|
||||
- v5
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -8786,7 +8796,9 @@ properties:
|
||||
description: Array of NATS subjects to subscribe to
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -8876,7 +8888,9 @@ properties:
|
||||
description: Name of the PostgreSQL logical replication slot to use
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -9123,7 +9137,9 @@ properties:
|
||||
description: Array of SQS message attribute names to include with each message
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
@@ -9322,7 +9338,9 @@ properties:
|
||||
The extracted value replaces {{state}} in the heartbeat message.
|
||||
error_handler_path:
|
||||
type: string
|
||||
description: Path to a script or flow to run when the triggered job fails
|
||||
description: Path to a script to run when the triggered job fails. A bare path,
|
||||
without the script/ or flow/ prefix a schedule error handler takes; it cannot
|
||||
be a flow.
|
||||
error_handler_args:
|
||||
type: object
|
||||
description: The arguments to pass to the script or flow
|
||||
|
||||
Reference in New Issue
Block a user