Skip to content

Commit 1df1171

Browse files
authored
chore(ai-skills): add release preparation skills (#1735)
1 parent 0c4d13a commit 1df1171

8 files changed

Lines changed: 927 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# changelog-to-jira
2+
3+
Creates missing DGW Jira tickets from `CHANGELOG.md` entries, transitions them to Done, and writes the ticket links back into the file.
4+
5+
## Prerequisites
6+
7+
### PowerShell 7+
8+
9+
```powershell
10+
winget install Microsoft.PowerShell
11+
```
12+
13+
### JiraPS module
14+
15+
```powershell
16+
Install-Module JiraPS -Scope CurrentUser
17+
```
18+
19+
### Atlassian API token
20+
21+
Generate one at <https://id.atlassian.com/manage-profile/security/api-tokens>.
22+
23+
The token must have the following Jira scopes:
24+
25+
| Scope | Why |
26+
|---|---|
27+
| `read:jira-work` | Read issues and transitions |
28+
| `write:jira-work` | Create issues, add links, perform transitions |
29+
30+
### Environment variables
31+
32+
Add to your PowerShell profile (`$PROFILE`):
33+
34+
```powershell
35+
$env:JIRA_URL = "https://devolutions.atlassian.net"
36+
$env:JIRA_EMAIL = "you@devolutions.net"
37+
$env:JIRA_API_TOKEN = "your-api-token-here"
38+
```
39+
40+
### Atlassian MCP server
41+
42+
The skill uses the Atlassian remote MCP server for assignee lookups. Add it to Claude Code:
43+
44+
```bash
45+
claude mcp add --transport sse claude_ai_Atlassian https://mcp.atlassian.com/v1/sse
46+
```
47+
48+
This registers a server named `claude_ai_Atlassian`, which is the name the skill expects. On first use, Claude Code will prompt you to authenticate via OAuth.
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
---
2+
name: changelog-to-jira
3+
description: Creates missing DGW Jira tickets from CHANGELOG.md entries and updates the file with the new ticket links.
4+
compatibility:
5+
tools:
6+
- Bash
7+
- Read
8+
- Edit
9+
- mcp__claude_ai_Atlassian__lookupJiraAccountId
10+
- mcp__claude_ai_Atlassian__getJiraIssue
11+
- mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql
12+
- mcp__claude_ai_Atlassian__getIssueLinkTypes
13+
- mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadata
14+
---
15+
16+
# Changelog to Jira Skill
17+
18+
This skill reads `CHANGELOG.md`, identifies entries that don't have a `DGW-*` Jira ticket, groups similar entries together, creates them in the DGW project, infers the assignee from the commit author, transitions them to Done, and updates `CHANGELOG.md` with the new ticket links.
19+
20+
## Scope
21+
22+
**Only process entries for these components** (text inside `_italics_`):
23+
- `dgw` — Devolutions Gateway core
24+
- `installer` — Devolutions Gateway installer
25+
- `agent` — Devolutions Agent
26+
- `agent-installer` — Agent installer
27+
28+
Skip entries for any other component (e.g., `webapp`, `jetsocat`, `crates`).
29+
30+
**Always default to the latest release** — the first `## VERSION (DATE)` block in the file.
31+
32+
## Audience
33+
34+
Ticket descriptions are for **QA technicians, support technicians, and marketing people**. Write them from a consumer perspective — what changed for the user, not how it was implemented. Avoid internal code references, crate names, and architecture notes.
35+
36+
**Length:** calibrate to the complexity of the change.
37+
- A bug fix or minor improvement: 1–2 sentences is enough.
38+
- A new feature that requires configuration or has non-obvious behaviour: write as much as needed. Include what the feature does, how to enable or configure it, and any relevant defaults or caveats. This gives QA and support enough context to test and explain it without needing to read the code.
39+
40+
**Examples:**
41+
42+
Bug fix (short):
43+
> Fixed a crash that could occur when the Gateway service was restarted while an active session was recording.
44+
45+
New feature needing configuration (longer):
46+
> Gateway and Agent now support outbound proxy configuration for all network traffic. The proxy mode is controlled by the `Proxy.Mode` field in the configuration file:
47+
> - `System` (default): auto-detects proxy settings from environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) or system settings (WinHTTP on Windows, `/etc/sysconfig/proxy` on RHEL/SUSE, system preferences on macOS).
48+
> - `Manual`: uses explicitly configured URLs. Set `Proxy.Http`, `Proxy.Https`, or `Proxy.All` to a proxy URL (e.g. `http://proxy.corp:8080` or `socks5://proxy.corp:1080`).
49+
> - `Off`: disables proxy entirely.
50+
>
51+
> HTTP, HTTPS, SOCKS4, and SOCKS5 proxies are supported.
52+
53+
## Workflow
54+
55+
### Step 1: Read and Parse CHANGELOG.md
56+
57+
Read `CHANGELOG.md` from the current working directory. Take the first `## VERSION (DATE)` block.
58+
59+
**Entry format:**
60+
```
61+
## VERSION (DATE)
62+
63+
### Section (Features / Bug Fixes / Security / Performance / etc.)
64+
65+
- _component_: short description ([#PR](github-pr-url)) ([commit](commit-url)) ([TICKET-ID](jira-url))
66+
67+
Optional multi-line body with more detail.
68+
```
69+
70+
Parse each entry into:
71+
- `section`: Features / Bug Fixes / Security / Performance / etc.
72+
- `component`: text inside `_italics_`
73+
- `description`: the short description text
74+
- `body`: optional indented multi-line description
75+
- `github_pr`: PR number if present (e.g., `#1676`)
76+
- `commit_hash`: short hash from the commit URL if present
77+
- `existing_tickets`: all Jira ticket IDs found (pattern: `[A-Z]+-\d+` with `atlassian.net/browse` URL)
78+
79+
Filter to only entries whose `component` is one of: `dgw`, `installer`, `agent`, `agent-installer`.
80+
81+
### Step 2: Classify and Group Entries
82+
83+
#### Classify each entry
84+
85+
| Case | Condition | Action |
86+
|---|---|---|
87+
| **Already done** | Has a `DGW-*` ticket | Skip |
88+
| **Cross-project** | Has a ticket from another project (e.g., `ARC-353`, `PI-651`) | Create a DGW ticket linked to the original |
89+
| **Missing** | No Jira ticket | Create a new DGW ticket |
90+
91+
#### Group similar entries into a single ticket
92+
93+
Before planning ticket creation, look for entries that describe **the same underlying change** and should be represented by one ticket rather than several. Group them when:
94+
95+
- They share the same PR number (most reliable signal — same code change, multiple components affected)
96+
- They are clearly two sides of the same feature (e.g., both `dgw` and `agent` entries describe adding the same capability)
97+
- The descriptions are semantically equivalent (same fix or feature, slightly different wording)
98+
99+
When grouping, create **one ticket** that:
100+
- Lists all affected components in the summary: `[dgw, agent] Feature description`
101+
- Has a description that covers all components
102+
- Maps CHANGELOG.md lines for all grouped entries to this single ticket
103+
104+
Do not force groupings. When in doubt, create separate tickets.
105+
106+
### Step 3: Show the Plan
107+
108+
Before creating anything, show a summary table and wait for confirmation:
109+
110+
```
111+
Latest release: 2026.1.0 (2026-02-23)
112+
113+
Will CREATE (no ticket):
114+
[Features] dgw: Add CredSSP certificate configuration keys (#1676)
115+
[Bug Fixes] agent-installer: Specify ARM64 platform for ARM64 installer
116+
117+
Will CREATE (grouped — same change):
118+
[Features] dgw + agent: RDM pipe passthrough logic (#1701)
119+
• dgw: add pipe passthrough for RDM
120+
• agent: handle pipe passthrough messages from RDM
121+
122+
Will CREATE + LINK (cross-project ticket):
123+
[Features] agent: RDM messages and pipe passthrough logic → PI-651
124+
125+
Already have DGW tickets (skipping):
126+
DGW-341 — Improve real-time performance of session shadowing
127+
128+
Proceed?
129+
```
130+
131+
### Step 4: Infer Assignee from Commit Author
132+
133+
For every entry that needs a new ticket (missing or cross-project), infer the assignee by looking up the commit author in git and resolving them to a Jira account.
134+
135+
**For entries with a commit hash:**
136+
137+
```bash
138+
git log --format="%ae %an" -1 <commit-hash>
139+
```
140+
141+
This gives you the author's email and name. Then look up their Jira account:
142+
143+
```
144+
mcp__claude_ai_Atlassian__lookupJiraAccountId → query = "<author email or name>"
145+
```
146+
147+
Use the email first — it's the most reliable identifier. If no match, try the display name.
148+
149+
**For cross-project entries:** Also fetch the original ticket's assignee (`getJiraIssue → assignee.accountId`) as a fallback if the commit lookup yields no result. Prefer the commit author when both are available.
150+
151+
**If no commit hash is available**, or the author lookup returns no result, omit the assignee field — do not block ticket creation.
152+
153+
**Cache the results** — if two entries share the same commit author, reuse the resolved `accountId` without a second lookup.
154+
155+
### Step 5: Build the ticket plan and run the script
156+
157+
Construct a `jira-plan.json` file in the repo root with all tickets to create:
158+
159+
```json
160+
{
161+
"tickets": [
162+
{
163+
"id": "t1",
164+
"summary": "[dgw] Add CredSSP certificate configuration keys",
165+
"issuetype": "Story",
166+
"description": "Consumer-facing description. Length should match complexity — see Audience section.",
167+
"assignee_account_id": "557058:eeb3e2d6-ef7a-463e-9d9e-5834dd925adb",
168+
"cross_project_link": null
169+
},
170+
{
171+
"id": "t2",
172+
"summary": "[dgw, agent] RDM pipe passthrough logic",
173+
"issuetype": "Bug",
174+
"description": "...",
175+
"assignee_account_id": null,
176+
"cross_project_link": "PI-651"
177+
}
178+
]
179+
}
180+
```
181+
182+
**Issue type by section:**
183+
| Section | `issuetype` |
184+
|---|---|
185+
| Features | `Story` |
186+
| Bug Fixes | `Bug` |
187+
| Security | `Bug` |
188+
| Performance | `Story` |
189+
| Other | `Task` |
190+
191+
**Summary format:** `[component] Capitalized short description`
192+
- Single entry: `[dgw] Add CredSSP certificate configuration keys`
193+
- Grouped entry: `[dgw, agent] Add CredSSP certificate configuration keys`
194+
195+
**Description:** 2–4 sentences, consumer-facing. Rewrite for a non-technical audience. For cross-project entries, append: `Related ticket: ARC-353`.
196+
197+
Keep a local map of `id → CHANGELOG.md line(s)` — you will need it in Step 7 to write back the ticket keys.
198+
199+
Then run the script, capturing its JSON output:
200+
201+
```powershell
202+
pwsh <skill-dir>/scripts/invoke-jira.ps1 -PlanFile jira-plan.json
203+
```
204+
205+
The script handles everything mechanical: creating each ticket, linking cross-project tickets, walking the DGW workflow to Done (`Backlog → To Do → Development → Reviewing → Done`), and deleting `jira-plan.json` when done.
206+
207+
The result JSON is written to stdout:
208+
209+
```json
210+
{
211+
"created": [
212+
{ "id": "t1", "key": "DGW-400" },
213+
{ "id": "t2", "key": "DGW-401" }
214+
],
215+
"errors": []
216+
}
217+
```
218+
219+
If `errors` is non-empty, report the failures to the user before continuing.
220+
221+
### Step 7: Update CHANGELOG.md
222+
223+
After creating all tickets, automatically update `CHANGELOG.md` to append the new ticket links to each affected entry line.
224+
225+
Entry format for the appended link: `([DGW-400](https://devolutions.atlassian.net/browse/DGW-400))`
226+
227+
It goes at the end of the `-` line, after existing links. For grouped entries, add the same ticket link to **all** the CHANGELOG.md lines that were grouped together. Example:
228+
229+
Before:
230+
```
231+
- _dgw_: add CredSSP certificate configuration keys ([#1676](...)) ([443e5f0b02](...))
232+
```
233+
After:
234+
```
235+
- _dgw_: add CredSSP certificate configuration keys ([#1676](...)) ([443e5f0b02](...)) ([DGW-400](https://devolutions.atlassian.net/browse/DGW-400))
236+
```
237+
238+
### Step 8: Summary Report
239+
240+
```
241+
Created N DGW tickets for version 2026.1.0:
242+
DGW-400: [dgw] Add CredSSP certificate configuration keys (assignee: Alice)
243+
DGW-401: [agent-installer] Specify ARM64 platform for ARM64 installer (assignee: Bob)
244+
DGW-402: [dgw, agent] RDM pipe passthrough logic (grouped 2 entries) (assignee: Carol)
245+
DGW-403: [agent] RDM messages and pipe passthrough logic (→ PI-651) (assignee: Dave)
246+
247+
All tickets transitioned to Done.
248+
249+
Skipped 1 (already had DGW ticket):
250+
DGW-341 — Improve real-time performance of session shadowing
251+
252+
CHANGELOG.md updated with new ticket links.
253+
```
254+
255+
## Edge Cases
256+
257+
- **Multi-component entries** like `_dgw,agent_`: Process it (both components are in scope), use the combined form in the summary.
258+
- **No body text**: Write a 1-sentence description from the summary alone — don't leave it blank.
259+
- **Unknown link type**: Call `mcp__claude_ai_Atlassian__getIssueLinkTypes` to find "relates to".
260+
- **Unknown issue types**: Call `mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadata` for project `DGW`.
261+
- **Commit author not in Jira**: If `lookupJiraAccountId` returns no results (e.g., a contractor or external contributor), skip the assignee — don't block ticket creation.
262+
- **No "Done" transition**: If the project uses different terminal state names, pick the closest one. If genuinely ambiguous, skip transitioning and note it in the summary.
263+
264+
## Atlassian MCP Tools
265+
266+
These are the only MCP tools still needed — ticket creation, linking, and transitions are handled by the PowerShell script.
267+
268+
- `mcp__claude_ai_Atlassian__lookupJiraAccountId` — resolve a commit author's email or name to a Jira account ID (Step 4)
269+
- `mcp__claude_ai_Atlassian__getJiraIssue` — fetch cross-project ticket details (assignee fallback, Step 4)
270+
- `mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql` — search existing tickets if needed

0 commit comments

Comments
 (0)