Run hurl test files in dependency order using frontmatter metadata
Project description
Hurl Orchestrator
A dependency-aware task runner for Hurl. It allows you to treat API requests as a Directed Acyclic Graph (DAG), managing complex authentication flows and resource creation without redundant executions or manual variable passing.
Getting Started
Install the package and verify that hurl is available on your PATH.
pip install hurl-orchestra
hurl --version
Run the orchestrator from the current directory:
hurl-orchestra
Or point it at a specific test folder:
hurl-orchestra ./tests
For a quick diagram of your DAG instead of execution, use:
hurl-orchestra --diagram ./tests
Core Philosophy
- Explicit over Implicit: Every dependency must be declared. This ensures that if a test fails, you know exactly which parent requirement was not met.
- Namespaced Variables: Outputs are tied to the ID of the node that produced them (
auth_token), preventing variable collisions in large suites. - Reusable Logic: Run the same Hurl file multiple times with different identities (e.g.,
admin_loginvsuser_login) using the alias syntax.
1. Setup
Requirements
- Python 3.11+
- Hurl installed and available on your
PATH
Install
pip install hurl-orchestra
Project Structure
Place your .hurl files in a directory. You can optionally include a .env file for global variables.
tests/
├── .env # Global variables (base_url, etc.)
├── auth.hurl # Reusable auth logic
└── create_user.hurl # Depends on auth
2. Defining Hurl Files
Each .hurl file uses YAML frontmatter to define its place in the graph.
Creating and formatting a .hurl file
A .hurl file consists of:
- Optional YAML frontmatter wrapped in
---markers - The Hurl request and assertions body
Required frontmatter fields:
id— unique node name for this testoutputs— list of capture names this test publishesdeps— list of upstream node IDs or alias definitionspriority— optional integer that influences ordering within a ready wave
Example file structure:
---
id: my_test
outputs: [token, session_id]
deps: [auth]
priority: 1
---
GET https://api.example.com/resource
Authorization: Bearer {{auth_token}}
HTTP 200
Aliases let you reuse the same template under multiple names and run each alias separately:
---
id: admin_flow
deps:
- auth: admin_login
- auth: user_login
---
GET https://api.example.com/admin
Authorization: Bearer {{admin_login_token}}
The Producer (auth.hurl)
Define an id and a list of outputs you want to share with other tests.
---
id: auth
outputs: [token]
---
POST https://api.com/login
[Captures]
token: jsonpath "$.token"
HTTP 200
The Consumer (profile.hurl)
List the id of the producer in deps. Access the variable using the {id}_{variable} syntax.
---
id: get_profile
deps: [auth]
---
GET https://api.com/profile
Authorization: Bearer {{auth_token}}
HTTP 200
3. Running
hurl-orchestra # runs against the current directory
hurl-orchestra ./tests # runs against a specific directory
hurl-orchestra auth.hurl profile.hurl # run specific files only
Passing Hurl Flags
Any flag that Hurl itself accepts can be passed directly and it will be forwarded to every invocation:
hurl-orchestra ./tests --verbose
hurl-orchestra ./tests --variable host=localhost --retry 3
hurl-orchestra auth.hurl profile.hurl --variable env=staging
This works the same as calling hurl with those flags — the orchestrator passes them through verbatim.
Running Specific Files
When you pass .hurl files directly, the orchestrator still respects their deps, outputs, and all other frontmatter — only the file discovery step changes. Files you list are the only ones loaded as templates, so any deps they declare must also be among the files you pass.
If the diagram output file already exists, use --diagram-overwrite to replace it.
# Runs auth.hurl first (because profile.hurl depends on it), then profile.hurl
hurl-orchestra auth.hurl profile.hurl
Reports
After every run, the orchestrator writes a zip archive containing the raw hurl JSON reports for every node that executed. Each node gets its own subdirectory inside the zip, named after its ID.
report.zip
├── auth/
│ ├── report.json
│ └── store/
└── create_user/
├── report.json
└── store/
The zip is written even if the run fails, so partial results are preserved for debugging. Use --report-zip to change the output filename:
hurl-orchestra ./tests --report-zip ci-run.zip
Visualising the DAG
Pass --diagram to generate a Markdown file with a Mermaid flowchart instead of running tests:
hurl-orchestra --diagram ./tests # writes diagram.md
hurl-orchestra --diagram ./tests --diagram-output pipeline.md
hurl-orchestra --diagram auth.hurl profile.hurl --diagram-output - # stdout
hurl-orchestra --diagram ./tests --diagram-output diagram.md --diagram-overwrite
The output file contains:
- Flowchart — all nodes with edges showing dependency direction. Node labels include the output count and, when non-zero, the priority.
4. Advanced Features
Rerunning Dependencies (Aliasing)
If you need to run the same logic twice (e.g., to get two different tokens), use the template: alias syntax in your deps.
---
id: admin_test
deps:
- auth: admin_login # Runs auth.hurl as "admin_login"
- auth: user_login # Runs auth.hurl as "user_login"
---
GET /admin
Authorization: {{admin_login_token}}
Execution Priority
By default, nodes at the same dependency level run in an unspecified order. Use priority to control that order without adding artificial dependencies.
| Value | Effect |
|---|---|
positive (e.g. 2) |
runs earlier than nodes with lower or no priority |
0 (default) |
neutral |
negative (e.g. -1) |
runs later than neutral nodes |
Example: you have a create, a search, and a delete that are all independent. Without priority they could run in any order — if delete runs first it breaks search.
---
id: create
priority: 1 # runs first
---
---
id: search
# priority defaults to 0
---
---
id: delete
priority: -1 # runs last
---
Priority only affects ordering within the same wave. It never overrides actual deps — a node always waits for its dependencies regardless of its priority value.
Global Environment (.env)
The orchestrator automatically detects a .env file in the test directory. Variables defined here are available to all Hurl files without being declared in the frontmatter.
# .env
base_url=https://staging.api.com
5. Execution Flow
When you run hurl-orchestra, the tool performs the following steps:
- Discovery: Scans for all
.hurlfiles and reads their metadata. - Graph Construction: Builds an execution map. If you used an alias, it "clones" that template into a unique node.
- Validation: Ensures there are no circular dependencies (e.g., A depends on B, and B depends on A).
- Execution:
- Processes nodes wave by wave — each wave contains all nodes whose dependencies are satisfied.
- Within each wave, nodes are sorted by
priority(highest first). - Captures output variables into a shared pool.
- Injects required variables into downstream tests via Hurl's
--variableflag. - Stops immediately if any test fails to prevent cascade failures.
6. Troubleshooting
"Circular dependency detected"
Your deps create an infinite loop. Check your frontmatter to ensure you aren't accidentally requiring a file that eventually requires the current file.
"FAILED: node_id"
The orchestrator will output the stderr from the Hurl binary. This usually means an assertion failed within the .hurl file itself or a network error occurred.
"Node depends on missing node"
Ensure the id in your deps matches the id defined in the target Hurl file's frontmatter (or its filename stem if no id is provided).
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hurl_orchestra-0.6.0.tar.gz.
File metadata
- Download URL: hurl_orchestra-0.6.0.tar.gz
- Upload date:
- Size: 18.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0712244303f40927183c2bbe416b7e1949dfa379abe61ce6b070906cff6198e6
|
|
| MD5 |
9f594399fdd79ca0f19b370177332aa8
|
|
| BLAKE2b-256 |
65cf60e34986df9bbf9da80a2bb1739e5de052f57601702543e987cfa10cd318
|
Provenance
The following attestation bundles were made for hurl_orchestra-0.6.0.tar.gz:
Publisher:
publish.yml on klaygomes/hurl-orchestra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hurl_orchestra-0.6.0.tar.gz -
Subject digest:
0712244303f40927183c2bbe416b7e1949dfa379abe61ce6b070906cff6198e6 - Sigstore transparency entry: 1239495051
- Sigstore integration time:
-
Permalink:
klaygomes/hurl-orchestra@b5cf4d4db6f4241437cf706c149b77462a65ec30 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/klaygomes
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b5cf4d4db6f4241437cf706c149b77462a65ec30 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hurl_orchestra-0.6.0-py3-none-any.whl.
File metadata
- Download URL: hurl_orchestra-0.6.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c160ba921fd0ea5e81923ae35e46a917ae5ff82e53c061b75003da4aa6b8e3c8
|
|
| MD5 |
35e7730182aac0c5d14ecf432be39959
|
|
| BLAKE2b-256 |
4a47b04751c4e318026416703967a01e22b0f5574a0249caed9f1c0c6c4a10a9
|
Provenance
The following attestation bundles were made for hurl_orchestra-0.6.0-py3-none-any.whl:
Publisher:
publish.yml on klaygomes/hurl-orchestra
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hurl_orchestra-0.6.0-py3-none-any.whl -
Subject digest:
c160ba921fd0ea5e81923ae35e46a917ae5ff82e53c061b75003da4aa6b8e3c8 - Sigstore transparency entry: 1239495052
- Sigstore integration time:
-
Permalink:
klaygomes/hurl-orchestra@b5cf4d4db6f4241437cf706c149b77462a65ec30 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/klaygomes
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b5cf4d4db6f4241437cf706c149b77462a65ec30 -
Trigger Event:
push
-
Statement type: