Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- **Hyphenated saved-query param names** — the workflow template
resolver now accepts hyphens in identifiers, so references like
`${{ params.vendor-no }}` substitute correctly. Previously the regex
matched only `[\w.]`, silently leaving the literal `${{ … }}` token
in the rendered filter (BC then 400'd or, worse, returned mismatched
rows). Affects both `bcli q` saved queries and `bcli batch`
workflows.

## [0.2.0] — 2026-05-06

### Added
Expand Down
6 changes: 4 additions & 2 deletions src/bcli/workflow/_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
from bcli.workflow._models import WorkflowContext

# Matches ${{ steps.name.path }} or ${{ params.key }}
REFERENCE_PATTERN = re.compile(r"\$\{\{\s*(steps|params)\.([\w.]+)\s*\}\}")
# Identifier set: word chars + dot (for nested step output paths) + hyphen
# (param names like ``vendor-no`` are commonly used by saved queries).
REFERENCE_PATTERN = re.compile(r"\$\{\{\s*(steps|params)\.([\w.\-]+)\s*\}\}")

# Same pattern, but must be the *entire* string (for type preservation).
FULL_REFERENCE_PATTERN = re.compile(
r"^\s*\$\{\{\s*(steps|params)\.([\w.]+)\s*\}\}\s*$"
r"^\s*\$\{\{\s*(steps|params)\.([\w.\-]+)\s*\}\}\s*$"
)


Expand Down
10 changes: 10 additions & 0 deletions tests/test_workflow/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ def test_bool_param_type_preserved(self):
ctx = _ctx(params={"active": True})
assert resolve_references("${{ params.active }}", ctx) is True

def test_hyphenated_param_name(self):
ctx = _ctx(params={"vendor-no": "V00011", "ship-no": "SHIP0045"})
# Embedded reference with hyphenated key
assert (
resolve_references("vendor eq '${{ params.vendor-no }}'", ctx)
== "vendor eq 'V00011'"
)
# Full-string reference with hyphenated key (type preservation path)
assert resolve_references("${{ params.ship-no }}", ctx) == "SHIP0045"

def test_mixed_string_interpolation(self):
ctx = _ctx(params={"vendor_no": "V00011"})
result = resolve_references("Invoice for ${{ params.vendor_no }}", ctx)
Expand Down
Loading