Skip to content

Commit b1cf635

Browse files
authored
Adjust jira skills for handling formatted descriptions (#31)
* Adjust jira skills for handling formatted descriptions Assisted-by: Claude Opus 4.6 Signed-off-by: John Collier <jcollier@redhat.com> * fix: apply ruff formatting to jira-wiki-to-adf.py Assisted-by: Claude Opus 4.6 * fix: address PR #31 review feedback from Paul - to-issue.md: story_points → customfield_10028 (field cannot be set via display name on writes) - SKILL.md Gotcha #6: point agents at jira-wiki-to-adf.py instead of hand-rolling ADF - to-epic/feature/issue.md: use $(mktemp) variable for ADF output files for portability - to-epic/feature/issue.md: drop /tmp/ prefix from converter input paths (bare filename works cross-platform) - to-epic.md: soften parent link wording — both customfield_10018 and parent.key work; warn only against issuelinks - jira-wiki-to-adf.py: switch to argparse with --help, add encoding="utf-8" on file I/O, remove unused sys import - tests/unit/test_jira_wiki_to_adf.py: 10 unit tests against epic-example.txt (heading, bulletList, taskList, inline marks) - acli-commands.md, templates.md, support.md: fix old plain-text create flow to use ADF conversion step Assisted-by: claude-sonnet-4-6 --------- Signed-off-by: John Collier <jcollier@redhat.com>
1 parent ad5f9a2 commit b1cf635

9 files changed

Lines changed: 401 additions & 40 deletions

File tree

skills/rhdh-jira/SKILL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Before attempting any REST API or GraphQL call:
8888
| `scripts/parse_issues.py` | Flatten, enrich, and filter acli JSON output. Solves the core problem: `acli search --json` can't return custom fields (team, story points, sprint). Pipe search results in, get clean data out. Use `--enrich` to fetch full fields, `-f team="X"` to filter by team. |
8989
| `scripts/command-metadata.json` | Single source of truth for sub-command descriptions and argument hints. |
9090
| `scripts/validate_components.py` | Validate `references/fields.md` component catalog against live Jira projects (RHIDP + RHDHPLAN). Reports drift in both directions. Run with `--json` for structured output. |
91+
| `scripts/jira-wiki-to-adf.py` | Convert a filled Jira wiki markup template to Atlassian Document Format JSON for use with `acli --description-file`. Handles `hN.` headings, `* ` bullets, `# ` ordered lists, `(?)` / `(/)` task items, `*bold*`, `_italic_`, `{{monospace}}`, backtick code. Usage: `python scripts/jira-wiki-to-adf.py input.txt > output.adf.json` |
9192

9293
## Projects
9394

@@ -150,7 +151,7 @@ Load only what the current task requires.
150151
3. **`--yes` is mandatory for mutations.** All `edit`, `transition`, `assign`, and `link create` commands prompt interactively without it. Always pass `--yes`.
151152
4. **`--fields` is restrictive on search.** Only accepts `key`, `summary`, `status`, `assignee`, `issuetype`, `priority`, `description`, `labels`. For components, sprint, fixVersions, and all custom fields — use `--json` or `scripts/parse_issues.py --enrich`.
152153
5. **Team field has two JQL syntaxes.** `customfield_10001` cannot be used in JQL WHERE clauses. However, `"Team[Team]" = {teamId}` (using the team UUID, not display name) works. Use the UUID syntax for JQL filtering; use `customfield_10001.name` in post-processing only when you need the display name from JSON output.
153-
6. **ADF vs plain text.** Reading descriptions via `--json` returns Atlassian Document Format (nested JSON). Creating/editing with `--description` accepts plain text. Don't try to round-trip ADF through `--description`.
154+
6. **ADF is required for formatted descriptions.** Reading descriptions via `--json` returns Atlassian Document Format (nested JSON). Jira Cloud's editor is ADF-native — plain text and Jira wiki markup (`h1.`, `*bold*`) both render as literal characters in the UI. For formatted descriptions, fill a wiki markup template then run `scripts/jira-wiki-to-adf.py <input.txt> <output.json>` to convert to ADF, then pass via `--description-file`. Both `acli create` and `acli edit` accept ADF JSON via `--description-file`. Do not use Jira wiki markup in description files expecting it to render.
154155
7. **Acceptance Criteria field is almost always null.** Scan the description for "Requirements", "Acceptance Criteria", or bullet-style criteria instead of checking `customfield_10718`.
155156
8. **`--enrich` is MANDATORY for custom fields AND labels.** Both `acli search --json` and `acli view KEY --json` (without `--fields "*all"`) return only basic fields (assignee, issuetype, priority, status, summary). Labels, story points, team, sprint, size, and components will all appear as empty/null — looking like the data isn't set when it actually is. Always use `scripts/parse_issues.py --enrich` to get custom field data. Skipping `--enrich` is the #1 cause of false "missing data" reports.
156157
9. **`acli` cannot set arbitrary custom fields.** `acli jira workitem edit` does not have a `--custom` flag. Fields like Team, Size, Story Points, and Release Note Type can only be updated via the Jira REST API. Use `PUT /rest/api/3/issue/{key}` with the field payload (see `references/rest-api-fallback.md` for curl examples and payload formats). Find the token file at `.jira-token` next to the `acli` executable (discover the path with `readlink -f "$(which acli)"` or `where acli`). Never read the token file into context.
@@ -162,6 +163,7 @@ Load only what the current task requires.
162163
15. **Don't remove `rhdh-X.Y-candidate` labels.** Candidate labels track release targeting. Removing them without PM approval can silently drop a feature from release tracking.
163164
16. **Feature→Epic child links use Parent Link, not issuelinks.** Cross-project parent-child relationships (RHDHPLAN Feature → RHIDP Epic) use the `Parent Link` field (`customfield_10018`), not `issuelinks`. To find child Epics of a Feature, use JQL: `project = RHIDP AND type = Epic AND "Parent Link" = RHDHPLAN-XXX`. Checking `issuelinks` will show zero results and produce false "no child Epics" reports.
164165
17. **REST `/rest/api/3/search` returns 410 Gone.** This endpoint has been removed. Use POST to `/rest/api/3/search/jql` with body `{"jql": "...", "fields": [...], "maxResults": N}` instead. This only affects direct REST calls — `acli search` still works.
166+
18. **`acli workitem create` does not support `--priority`, `--component`, or `--yes`.** These flags exist on `edit`, `transition`, and `assign` but not on `create` — passing them causes "unknown flag" errors. After creating an issue, set priority, components, size (`customfield_10795`), and parent link (`customfield_10018`) together in a single `PUT /rest/api/3/issue/{key}` call.
165167

166168
## Error Handling
167169

skills/rhdh-jira/references/acli-commands.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ acli jira filter get --id 10001
240240
| Labels | Not available via `--fields` | Array of strings |
241241
| Fix versions | Not available via `--fields` | Array of version objects |
242242

243-
When writing descriptions, use `--description "plain text"`. When reading, be aware `--json` returns ADF — don't try to round-trip it.
243+
When writing formatted descriptions, fill a wiki markup template then convert with `scripts/jira-wiki-to-adf.py` and pass via `--description-file` (see Gotcha #6 in SKILL.md). When reading, be aware `--json` returns ADF — don't try to round-trip it.
244244

245245
## Custom Fields and `--enrich`
246246

skills/rhdh-jira/references/support.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,14 @@ When a product defect is identified:
7070
2. Comment on the RHDHSUPP issue with the RHDHBUGS link — this tells the customer when the fix is expected
7171

7272
```bash
73-
# Create the bug
73+
# Convert wiki markup to ADF (required — plain wiki text is not rendered by Jira)
74+
BUG_ADF=$(mktemp) # on Windows: use %TEMP% or Python tempfile
75+
python scripts/jira-wiki-to-adf.py bug_description.txt "$BUG_ADF"
76+
77+
# Create the bug (note: --yes does not exist on create, see Gotcha #18)
7478
acli jira workitem create --project RHDHBUGS --type Bug \
7579
--summary "Login fails when SSO token expires during session" \
76-
--description-file bug_description.txt \
80+
--description-file "$BUG_ADF" \
7781
--label "rhdh-customer" \
7882
--assignee "@me"
7983

@@ -96,9 +100,14 @@ When a support case reveals a missing capability:
96100
2. Encourage customer to follow up with their account team to prioritize with Product Management
97101

98102
```bash
103+
# Convert wiki markup to ADF (required — plain wiki text is not rendered by Jira)
104+
FEATURE_ADF=$(mktemp) # on Windows: use %TEMP% or Python tempfile
105+
python scripts/jira-wiki-to-adf.py feature_request.txt "$FEATURE_ADF"
106+
107+
# Create the feature request (note: --yes does not exist on create, see Gotcha #18)
99108
acli jira workitem create --project RHDHPLAN --type "Feature Request" \
100109
--summary "Support OIDC token refresh in admin console" \
101-
--description-file feature_request.txt
110+
--description-file "$FEATURE_ADF"
102111

103112
acli jira workitem link create --out RHDHSUPP-456 --in RHDHPLAN-123 --type "Related" --yes
104113
```

skills/rhdh-jira/references/templates.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ Implement SSO integration for admin console.
2626
...
2727
EOF
2828

29-
# Create the issue
29+
# Convert wiki markup to ADF (required — plain wiki text is not rendered by Jira)
30+
ISSUE_ADF=$(mktemp)
31+
python scripts/jira-wiki-to-adf.py issue-desc.txt "$ISSUE_ADF"
32+
33+
# Create the issue (note: --yes does not exist on create, see Gotcha #18)
3034
acli jira workitem create --project RHIDP --type Epic \
3135
--summary "SSO Integration for Admin Console" \
32-
--description-file issue-desc.txt \
33-
--assignee "@me" \
34-
--yes
36+
--description-file "$ISSUE_ADF" \
37+
--assignee "@me"
3538
```
3639

3740
## Field Requirements at Creation

skills/rhdh-jira/references/to-epic.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,27 +86,38 @@ Run the pre-creation check from `references/duplicates.md`. Search RHIDP Epics (
8686

8787
### Step 8 — Create Epic
8888

89-
Fill the template. Create the issue:
89+
Fill the template. Then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`:
90+
91+
```bash
92+
EPIC_ADF=$(mktemp) # on Windows: use %TEMP% or Python tempfile
93+
python scripts/jira-wiki-to-adf.py epic-filled.txt "$EPIC_ADF"
94+
```
95+
96+
Create the issue — note `--priority`, `--component`, and `--yes` do not exist on `create` (see Gotcha #18):
9097

9198
```bash
9299
acli jira workitem create --project RHIDP --type Epic \
93100
--summary "Epic summary" \
94-
--description-file /tmp/epic-desc.txt \
95-
--assignee "ACCOUNT_ID" \
96-
--priority "Major" \
97-
--component "Plugins" \
98-
--yes
101+
--description-file "$EPIC_ADF" \
102+
--assignee "ACCOUNT_ID"
99103
```
100104

101-
If a parent Feature exists, link via REST:
105+
Then set priority, components, size, and parent Feature link together in one REST call. Cross-project parent links accept either `customfield_10018` or `parent.key` — do not use `issuelinks` (see Gotcha #16):
102106

103107
```bash
104108
curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \
105-
-d '{"fields": {"parent": {"key": "RHDHPLAN-XXX"}}}' \
109+
-d '{
110+
"fields": {
111+
"priority": {"name": "Major"},
112+
"components": [{"name": "Catalog"}],
113+
"customfield_10795": {"value": "M"},
114+
"customfield_10018": "RHDHPLAN-XXX"
115+
}
116+
}' \
106117
"https://redhat.atlassian.net/rest/api/3/issue/RHIDP-XXX"
107118
```
108119

109-
Set Team and Size via REST — follow API preference order in SKILL.md.
120+
Set Team via REST — follow API preference order in SKILL.md.
110121

111122
### Step 9 — Comments
112123

skills/rhdh-jira/references/to-feature.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,37 @@ If a likely duplicate Feature is found, present it and ask: "This may already ex
9696

9797
### Step 7 — Create Feature
9898

99-
Fill the template with grill results. Save to a temp file. Create the issue:
99+
Fill the template with grill results. Save to a temp file. Then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`:
100+
101+
```bash
102+
FEATURE_ADF=$(mktemp) # on Windows: use %TEMP% or Python tempfile
103+
python scripts/jira-wiki-to-adf.py feature-filled.txt "$FEATURE_ADF"
104+
```
105+
106+
Create the issue — note `--priority` and `--yes` do not exist on `create` (see Gotcha #18):
100107

101108
```bash
102109
acli jira workitem create --project RHDHPLAN --type Feature \
103110
--summary "Feature summary" \
104-
--description-file /tmp/feature-desc.txt \
111+
--description-file "$FEATURE_ADF" \
105112
--assignee "ACCOUNT_ID" \
106-
--priority "Major" \
107-
--label "rhdh-2.1-candidate" \
108-
--yes
113+
--label "rhdh-2.1-candidate"
114+
```
115+
116+
Then set priority, Team, and Size together in one REST call:
117+
118+
```bash
119+
curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \
120+
-d '{
121+
"fields": {
122+
"priority": {"name": "Major"},
123+
"customfield_10795": {"value": "M"}
124+
}
125+
}' \
126+
"https://redhat.atlassian.net/rest/api/3/issue/RHDHPLAN-XXX"
109127
```
110128

111-
Set additional fields via REST if needed (Team, Size) — follow API preference order in SKILL.md.
129+
Set Team via REST — follow API preference order in SKILL.md.
112130

113131
### Step 8 — Comments
114132

@@ -132,7 +150,7 @@ If yes:
132150
2. For each team, invoke the `to-epic` workflow with context carried down from this Feature:
133151
- The Feature's scope, AC, and customer considerations are established — don't re-grill on these
134152
- The Epic grill narrows to: delivery scope for *this team*, dependencies, team-specific AC
135-
3. Each Epic is automatically linked to the parent Feature via `parent` field
153+
3. Each Epic is automatically linked to the parent Feature via `customfield_10018` (cross-project parent link — see Gotcha #16 and to-epic.md Step 8)
136154

137155
## Error Handling
138156

skills/rhdh-jira/references/to-issue.md

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,36 +119,49 @@ Run the pre-creation check from `references/duplicates.md`. Scope to the target
119119

120120
### Step 9 — Create Issue
121121

122-
Fill the template. Create the issue:
122+
Fill the appropriate template (`assets/templates/story.txt`, `task.txt`, or `bug.txt`) with grill results, then convert to ADF using the helper script (see Gotcha #6). `acli create` accepts ADF via `--description-file`:
123+
124+
```bash
125+
ISSUE_ADF=$(mktemp) # on Windows: use %TEMP% or Python tempfile
126+
python scripts/jira-wiki-to-adf.py story-filled.txt "$ISSUE_ADF"
127+
```
128+
129+
Create the issue — note `--priority`, `--component`, and `--yes` do not exist on `create` (see Gotcha #18):
123130

124131
```bash
125132
# Story
126133
acli jira workitem create --project RHIDP --type Story \
127134
--summary "Story summary" \
128-
--description-file /tmp/story-desc.txt \
129-
--assignee "ACCOUNT_ID" \
130-
--priority "Major" \
131-
--component "Plugins" \
132-
--yes
135+
--description-file "$ISSUE_ADF" \
136+
--assignee "ACCOUNT_ID"
133137

134138
# Bug (different project)
135139
acli jira workitem create --project RHDHBUGS --type Bug \
136140
--summary "Bug summary" \
137-
--description-file /tmp/bug-desc.txt \
138-
--priority "Critical" \
139-
--yes
141+
--description-file "$ISSUE_ADF"
140142

141143
# Spike (Task with prefix)
142144
acli jira workitem create --project RHIDP --type Task \
143145
--summary "SPIKE: Research multi-source catalog merging" \
144-
--description-file /tmp/spike-desc.txt \
145-
--assignee "ACCOUNT_ID" \
146-
--priority "Major" \
147-
--component "Plugins" \
148-
--yes
146+
--description-file "$ISSUE_ADF" \
147+
--assignee "ACCOUNT_ID"
148+
```
149+
150+
Then set priority, component, and story points together in one REST call:
151+
152+
```bash
153+
curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \
154+
-d '{
155+
"fields": {
156+
"priority": {"name": "Major"},
157+
"components": [{"name": "Plugins"}],
158+
"customfield_10028": 5
159+
}
160+
}' \
161+
"https://redhat.atlassian.net/rest/api/3/issue/RHIDP-YYY"
149162
```
150163

151-
If a parent Epic exists, link via REST:
164+
If a parent Epic exists, link via REST (same-project RHIDP→RHIDP uses native `parent` field):
152165

153166
```bash
154167
curl -s -X PUT -u "$AUTH" -H "Content-Type: application/json" \

0 commit comments

Comments
 (0)