diff --git a/features/steps/ticket_steps.py b/features/steps/ticket_steps.py index 276eb278..97cb0950 100644 --- a/features/steps/ticket_steps.py +++ b/features/steps/ticket_steps.py @@ -166,6 +166,26 @@ def step_ticket_linked_to(context, ticket_id, link_id): link_path.write_text(content) +@given(r'ticket "(?P[^"]+)" has tags \[(?P[^\]]+)\]') +def step_ticket_has_tags(context, ticket_id, tags): + """Set tags on a ticket using quoted YAML array format.""" + ticket_path = Path(context.test_dir) / '.tickets' / f'{ticket_id}.md' + content = ticket_path.read_text() + + # Format tags as quoted YAML array: ["tag1", "tag2"] + tags_list = [tag.strip().strip('"') for tag in tags.split(',')] + yaml_tags = '[' + ', '.join(f'"{tag}"' for tag in tags_list) + ']' + + # Check if tags field exists + if re.search(r'^tags:', content, re.MULTILINE): + content = re.sub(r'^tags:.*$', f'tags: {yaml_tags}', content, flags=re.MULTILINE) + else: + # Add tags field after priority + content = re.sub(r'^(priority: \d+)$', rf'\1\ntags: {yaml_tags}', content, flags=re.MULTILINE) + + ticket_path.write_text(content) + + @given(r'ticket "(?P[^"]+)" has a notes section') def step_ticket_has_notes(context, ticket_id): """Ensure ticket has a notes section.""" @@ -591,6 +611,40 @@ def step_jsonl_deps_is_array(context): raise AssertionError("No JSONL line with deps field found") +@then(r'the JSONL tags field should be a JSON array') +def step_jsonl_tags_is_array(context): + """Assert tags field in JSONL is an array.""" + lines = context.stdout.strip().split('\n') + assert lines, "No JSONL output" + + for line in lines: + if line.strip(): + data = json.loads(line) + if 'tags' in data: + assert isinstance(data['tags'], list), \ + f"tags field is not an array: {type(data['tags'])}\nActual value: {data['tags']}\nFull line: {line}" + return + raise AssertionError("No JSONL line with tags field found") + + +@then(r'the JSONL tags field should contain "(?P[^"]+)"') +def step_jsonl_tags_contains(context, tag): + """Assert tags field in JSONL contains a specific tag.""" + lines = context.stdout.strip().split('\n') + assert lines, "No JSONL output" + + for line in lines: + if line.strip(): + data = json.loads(line) + if 'tags' in data: + assert isinstance(data['tags'], list), \ + f"tags field is not an array: {type(data['tags'])}" + assert tag in data['tags'], \ + f"Tag '{tag}' not found in tags: {data['tags']}\nFull line: {line}" + return + raise AssertionError("No JSONL line with tags field found") + + @then(r'the dep tree output should have (?P[^\s]+) before (?P[^\s]+)') def step_dep_tree_order(context, first_id, second_id): """Assert that first_id appears before second_id in dep tree output.""" diff --git a/features/ticket_query.feature b/features/ticket_query.feature index 2ccafe70..e23fcdec 100644 --- a/features/ticket_query.feature +++ b/features/ticket_query.feature @@ -46,3 +46,13 @@ Feature: Ticket Query When I run "ticket query" Then the command should succeed And the JSONL deps field should be a JSON array + + Scenario: Query handles quoted tags in YAML + Given a ticket exists with ID "query-001" and title "Tagged ticket" + And ticket "query-001" has tags ["simplification-opportunity", "refactor"] + When I run "ticket query" + Then the command should succeed + And the output should be valid JSONL + And the JSONL tags field should be a JSON array + And the JSONL tags field should contain "simplification-opportunity" + And the JSONL tags field should contain "refactor" diff --git a/ticket b/ticket index 452adda4..71f3219d 100755 --- a/ticket +++ b/ticket @@ -1352,6 +1352,8 @@ cmd_query() { for (j = 1; j <= n; j++) { if (j > 1) printf "," gsub(/^ +| +$/, "", items[j]) + # Strip quotes from items (handles both single and double quotes) + gsub(/^["\047]|["\047]$/, "", items[j]) if (items[j] != "") printf "\"%s\"", items[j] } printf "]"