Control Flow
OrchStep provides conditionals, loops, switch/case, and task calling for workflow branching and iteration.
Conditionals (if/elif/else)
Section titled “Conditionals (if/elif/else)”Simple If (Skip When False)
Section titled “Simple If (Skip When False)”steps: - name: cleanup if: '{{ vars.clear_cache }}' func: shell do: rm -rf /tmp/cache/*Step is skipped when the condition evaluates to false.
If/Else with Inline Steps
Section titled “If/Else with Inline Steps”steps: - name: deploy if: '{{ eq vars.environment "production" }}' then: - name: deploy_prod func: shell do: echo "Production deployment with approval" else: then: - name: deploy_staging func: shell do: echo "Staging deployment"If/Elif/Else Chains
Section titled “If/Elif/Else Chains”steps: - name: set_log_level if: '{{ eq vars.environment "production" }}' then: - func: shell do: echo "LOG_LEVEL=error" elif: - if: '{{ eq vars.environment "staging" }}' then: - func: shell do: echo "LOG_LEVEL=warn" - if: '{{ eq vars.environment "development" }}' then: - func: shell do: echo "LOG_LEVEL=debug" else: then: - func: shell do: echo "LOG_LEVEL=info"If/Else with Task References
Section titled “If/Else with Task References”steps: - name: deploy if: '{{ eq vars.environment "production" }}' then: deploy_production else: deploy_stagingCondition Syntax
Section titled “Condition Syntax”Go Template expressions (wrapped in {{ }}):
| Operator | Example |
|---|---|
eq | '{{ eq vars.env "prod" }}' |
ne | '{{ ne vars.status "failed" }}' |
gt, ge | '{{ gt vars.count 10 }}' |
lt, le | '{{ lt vars.timeout 30 }}' |
and | '{{ and (eq vars.env "prod") (gt vars.replicas 2) }}' |
or | '{{ or (eq vars.mode "test") (eq vars.mode "dev") }}' |
not | '{{ not (empty vars.name) }}' |
JavaScript expressions (no {{ }} wrapper):
if: 'vars.count > 10 && vars.env === "production"'Switch/Case
Section titled “Switch/Case”For multi-way branching based on a single value:
steps: - name: route_deploy switch: value: '{{ vars.environment }}' cases: - when: 'production' then: - func: shell do: echo "Blue-green deploy" - when: 'staging' then: - func: shell do: echo "Rolling deploy" - when: ['development', 'testing'] then: - func: shell do: echo "Direct deploy" default: - func: shell do: echo "Unknown environment"Multi-Value Matching
Section titled “Multi-Value Matching”Use arrays to match multiple values in a single case:
switch: value: '{{ vars.status_code }}' cases: - when: [200, 201, 204] then: - func: shell do: echo "Success" - when: [400, 401, 403, 404] then: - func: shell do: echo "Client error" - when: [500, 502, 503] then: - func: shell do: echo "Server error, retry"Switch with Task References
Section titled “Switch with Task References”switch: value: '{{ vars.deploy_strategy }}' cases: - when: 'blue_green' task: deploy_blue_green - when: 'canary' task: deploy_canary - when: 'rolling' task: deploy_rolling default: - task: deploy_standardSimple List Iteration
Section titled “Simple List Iteration”steps: - name: deploy_regions loop: ["us-east-1", "eu-west-1", "ap-southeast-1"] func: shell do: echo "Deploying to {{ loop.item }}"Variable-Based List
Section titled “Variable-Based List”vars: servers: ["web1", "web2", "web3"]
steps: - name: restart loop: "{{ vars.servers }}" func: shell do: ssh {{ loop.item }} "systemctl restart app"Loop Variables
Section titled “Loop Variables”| Variable | Type | Description |
|---|---|---|
loop.item | any | Current item value |
loop.index | int | Zero-based index (0, 1, 2…) |
loop.index1 | int | One-based index (1, 2, 3…) |
loop.first | bool | True for first iteration |
loop.last | bool | True for last iteration |
loop.length | int | Total number of items |
loop.iteration | int | Alias for loop.index1 |
Full Loop Configuration
Section titled “Full Loop Configuration”steps: - name: process loop: items: "{{ vars.servers }}" as: server # Custom name (access via loop.server) on_error: continue # fail | continue | break until: '{{ eq loop.server.status "active" }}' # Break condition timeout: "30s" # Per-iteration timeout delay: "2s" # Delay between iterations collect_errors: true # Save error details func: shell do: deploy.sh {{ loop.server.host }}Count-Based Loop
Section titled “Count-Based Loop”steps: - name: retry_check loop: 5 func: shell do: echo "Attempt {{ loop.iteration }} of {{ loop.length }}"Range Loop
Section titled “Range Loop”steps: - name: scale loop: range: [1, 10, 2] # 1, 3, 5, 7, 9 func: shell do: echo "Instance {{ loop.item }}"Loop with Condition (Filter)
Section titled “Loop with Condition (Filter)”vars: servers: - name: web1 enabled: true - name: web2 enabled: false - name: db1 enabled: true
steps: - name: deploy_enabled loop: "{{ vars.servers }}" if: '{{ loop.item.enabled }}' func: shell do: echo "Deploying {{ loop.item.name }}"Until Condition
Section titled “Until Condition”Stop the loop when a condition becomes true:
steps: - name: wait_for_ready loop: count: 30 until: '{{ contains steps.wait_for_ready.output "READY" }}' delay: "2s" func: shell do: curl -s http://service/healthLoop with Task Call
Section titled “Loop with Task Call”tasks: deploy_all: steps: - name: deploy_regions loop: items: "{{ vars.regions }}" as: region on_error: continue task: deploy_single with: region_name: "{{ loop.region.name }}" replicas: "{{ loop.region.replicas }}"
deploy_single: steps: - func: shell do: deploy {{ vars.region_name }} --replicas {{ vars.replicas }}Task Calling
Section titled “Task Calling”Basic Task Call
Section titled “Basic Task Call”tasks: main: steps: - name: run_deploy task: deploy_service
deploy_service: steps: - func: shell do: echo "Deploying..."Task Call with Parameters
Section titled “Task Call with Parameters”Use with: to pass parameters that override the called task’s defaults:
tasks: main: steps: - name: deploy_staging task: deploy with: environment: staging replicas: 2
- name: deploy_production task: deploy with: environment: production replicas: 5
deploy: vars: environment: dev replicas: 1 steps: - func: shell do: echo "Deploying to {{ vars.environment }} ({{ vars.replicas }} replicas)"Output Encapsulation
Section titled “Output Encapsulation”Inner steps of conditional/switch blocks are isolated. Expose outputs via the parent outputs: field:
steps: - name: get_config if: '{{ eq vars.env "production" }}' then: - name: load_prod func: shell do: echo "prod-config-123" outputs: config_id: "{{ result.output }}" else: then: - name: load_dev func: shell do: echo "dev-config-456" outputs: config_id: "{{ result.output }}" outputs: final_config: '{{ steps.load_prod.config_id || steps.load_dev.config_id }}'
- name: use_config func: shell do: echo "Using {{ steps.get_config.final_config }}"