Repository navigation
feat: compose reusable workflow definitions - #346
Conversation
Demo: change a shared GitHub flow once and see consumers pick it upRun these commands from the PR branch with Forge's Redis available. Use a scratch Jira project key for 1. Inspect the built-in composition. The first render shows the reusable subworkflow and its named exits; the second shows the expanded Feature graph. DEMO_PROJECT=MYPROJ
ROOT=src/forge/workflow/declarative/definitions
uv run forge workflow render "$ROOT/github_pr_review.json"
uv run forge workflow render "$ROOT/feature.json"2. Publish and activate a project-owned copy of the shared flow. Publication stores an immutable revision; activation makes it available to new runs. uv run forge workflow publish "$DEMO_PROJECT" "$ROOT/github_pr_review.json" --actor demo --reason "shared flow demo"
uv run forge workflow activate "$DEMO_PROJECT" github_pr_review 1 --actor demo --reason "activate shared flow"3. Make a Feature workflow consume that project definition. This copies the complete built-in Feature process, gives it a separate name, and changes its include from jq '.metadata.name = "demo-feature" | .spec.includes[0].source = "project"' "$ROOT/feature.json" > /tmp/demo-feature.json
uv run forge workflow validate /tmp/demo-feature.json --project-key "$DEMO_PROJECT"
uv run forge workflow publish "$DEMO_PROJECT" /tmp/demo-feature.json --actor demo --reason "consume shared flow"
uv run forge workflow activate "$DEMO_PROJECT" demo-feature 5 --actor demo --reason "activate demo workflow"Record the digest printed by 4. Change the shared flow without republishing the consumer. This example changes the CI fix retry bound from 5 to 4. The expected digest is the active revision 1 source digest. OLD_DIGEST=$(uv run python -c 'from forge.workflow.declarative.loader import load_workflow_file; print(load_workflow_file("src/forge/workflow/declarative/definitions/github_pr_review.json").digest)')
jq '.metadata.revision = 2 | .spec.steps.attempt_ci_fix.retryBound = 4' "$ROOT/github_pr_review.json" > /tmp/demo-shared-v2.json
uv run forge workflow publish "$DEMO_PROJECT" /tmp/demo-shared-v2.json --actor demo --reason "CI retry update"
uv run forge workflow activate "$DEMO_PROJECT" github_pr_review 2 --expected-active-digest "$OLD_DIGEST" --actor demo --reason "roll out shared update"
uv run forge workflow validate /tmp/demo-feature.json --project-key "$DEMO_PROJECT"The final validation prints a different expanded digest while |
|
Just a question (I did not try this and I did not ask the AI). |
Code review —
|
|
@JoshSalomon Thanks for the detailed review. I addressed all nine findings in
On the expansion timing question: Forge resolves and pins the expanded graph when a new run starts. If P starts with S1 and S2 is activated before P reaches S, that run still uses S1. If S2 is activated while P is inside S, the run also stays on S1. A later new run uses S2. Publishing S2 alone does not change new runs until S2 is activated. Checkpoint resumes load the pinned expanded artifact, not today's active dependency. The focused regression suite passed (29 tests). The new PR CI run is still in progress; lint, contract tests, Helm lint, and integration tests have passed so far. |
Summary
Subworkflowdefinitions and same-project or built-in workflow includes, resolved into a flat graph before execution.Verification
LangGraph.ainvokehangs in this environment even for a minimal graph.