Skip to content

Commit 7f30755

Browse files
committed
fix: make workflow release checks deterministic
1 parent 8bffbb0 commit 7f30755

5 files changed

Lines changed: 15 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ jobs:
6363
with:
6464
python-version: "3.13"
6565

66-
- name: Install workflow contract dependency
67-
run: python -m pip install "pydantic>=2.10.0"
66+
- name: Install workflow contract dependencies
67+
run: python -m pip install "pydantic>=2.10.0" "httpx>=0.28.0" "sqlalchemy>=2.0.0" "python-dateutil>=2.9.0"
6868

6969
- name: Install dependencies
7070
run: |

frontend/lib/flow/store-slices.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
updateCanonicalNetworkScope,
1818
type CanonicalScopeId,
1919
} from "./store-canonical-actions"
20-
import { HISTORY_LIMIT, snapshot } from "./store-utils"
20+
import { HISTORY_LIMIT, snapshot, workflowNodeId } from "./store-utils"
2121
import { MAX_WORKFLOW_NODE_DEPTH } from "../workflow/node-hierarchy"
2222
import { parseWorkflowProject, type WorkflowProject, type WorkflowProjectNode } from "../workflow/schema"
2323
import type { WorkflowEdge, WorkflowNode } from "./types"
@@ -466,7 +466,7 @@ export function createSelectionActions(
466466

467467
const newNodes = clipboard.nodes.map((n) => {
468468
const canonicalNode = canonicalByCanvasId.get(n.id)
469-
const newLocalId = canonicalNode ? nanoid(8) : null
469+
const newLocalId = canonicalNode ? workflowNodeId() : null
470470
const newId = newLocalId
471471
? scopeId === null
472472
? newLocalId

frontend/lib/flow/store-utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { customAlphabet } from "nanoid"
12
import type { FlowSnapshot, FreehandStroke, WorkflowEdge, WorkflowNode } from "./types"
23
import type { WorkflowProject, WorkflowProjectEdge, WorkflowProjectNode } from "../workflow/schema"
34

45
export const HISTORY_LIMIT = 100
6+
export const workflowNodeId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 8)
57

68
export type FlowNetworkStackEntry = { nodeId: string; label: string; snapshot: FlowSnapshot }
79
export type FlowStoreSnapshot = FlowSnapshot & {

frontend/lib/flow/store.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
createSelectionActions,
3333
createWhiteboardActions,
3434
} from "./store-slices"
35-
import { snapshot } from "./store-utils"
35+
import { snapshot, workflowNodeId } from "./store-utils"
3636
import { PACKAGED_WORKFLOW_PROJECT } from "../workflow/collection-pipeline"
3737
import type { WorkflowProject } from "../workflow/schema"
3838
import { parseWorkflowProject, type AdapterBinding, type WorkflowProfile, type WorkflowProjectNode } from "../workflow/schema"
@@ -923,7 +923,7 @@ export const useFlowStore = create<FlowState>((set, get) => ({
923923
addPrimitiveNode: (item, position, runtimeCapability, options) => {
924924
if (!options?.suppressSnapshot) get().takeSnapshot()
925925
const { workflowProject, nodes, networkStack } = get()
926-
const localId = `${item.idPrefix}-${nanoid(6)}`
926+
const localId = `${item.idPrefix}-${workflowNodeId(6)}`
927927
const freePos = findFreePosition(nodes, position, { width: 196, height: 78 })
928928
const parentNetwork = networkStack.at(-1)
929929
const canonicalNode = canonicalNodeFromPrimitive(item, localId, freePos, runtimeCapability)

frontend/scripts/check-workflow-regressions.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ function sourceSection(source, start, end) {
9191
return source.slice(startIndex, endIndex)
9292
}
9393

94+
test('generated workflow node ids avoid reserved path separators', async () => {
95+
const { workflowNodeId } = await importTypeScript('lib/flow/store-utils.ts')
96+
for (let index = 0; index < 1_000; index += 1) {
97+
assert.doesNotMatch(workflowNodeId(), /::|__/)
98+
}
99+
})
100+
94101
test('right workflow dock derives its outline from graph structure and opens without a selection', async () => {
95102
const [{ buildWorkflowOutlineRows }, shortcuts, inspector, shell, effects] = await Promise.all([
96103
importTypeScript('lib/workflow/workflow-outline.ts'),

0 commit comments

Comments
 (0)