Detailed implementation guide for generating bug fix release notes from Jira and GitHub PRs
Automatically generates bug fix release notes by analyzing Jira bugs and linked GitHub PRs. Triggered by `/jira:create-release-note` command to extract cause, consequence, fix, and result from PR diffs and descriptions.
/plugin marketplace add openshift-eng/ai-helpers/plugin install jira@ai-helpersThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill provides detailed step-by-step implementation guidance for the /jira:create-release-note command, which automatically generates bug fix release notes by analyzing Jira bug tickets and their linked GitHub pull requests.
This skill is automatically invoked by the /jira:create-release-note command and should not be called directly by users.
gh) installed and authenticatedObjective: Retrieve the bug ticket and validate it's appropriate for release note generation.
Actions:
Fetch the bug using MCP:
mcp__atlassian__jira_get_issue(
issue_key=<issue-key>,
fields="summary,description,issuetype,status,issuelinks,customfield_12320850,customfield_12317313,comment"
)
Parse the response:
issuetype.name - verify it's "Bug"description - full bug description textissuelinks - array of linked issuescustomfield_12320850 - current Release Note Type (if already set)customfield_12317313 - current Release Note Text (if already set)comment.comments - array of comment objectsValidate issue type:
issuetype.name != "Bug", show warning:
Warning: {issue-key} is not a Bug (it's a {issuetype.name}).
Release notes are typically for bugs. Continue anyway? (yes/no)
Check if release note already exists:
customfield_12317313 is not empty, show warning:
This bug already has a release note:
---
{existing release note}
---
Do you want to regenerate it? (yes/no)
Objective: Extract the required Cause and Consequence sections from the bug description.
Bug Description Format:
Jira bug descriptions often follow this structure:
Description of problem:
{code:none}
<problem description>
{code}
Cause:
{code:none}
<root cause>
{code}
Consequence:
{code:none}
<impact>
{code}
Version-Release number of selected component (if applicable):
...
How reproducible:
...
Steps to Reproduce:
...
Actual results:
...
Expected results:
...
Parsing Strategy:
Look for "Cause:" section:
{code:none}, {code}, etc.Look for "Consequence:" section:
Alternative patterns:
Handle missing sections:
Bug description is missing the "Cause" section.
Would you like to:
1. Provide the Cause interactively
2. Update the bug description in Jira first
3. Cancel
Bug description is missing the "Consequence" section.
Would you like to:
1. Provide the Consequence interactively
2. Update the bug description in Jira first
3. Cancel
Interactive input (if user chooses option 1):
Example Parsing:
Input:
Description of problem:
{code:none}
The control plane operator crashes when CloudProviderConfig.Subnet is not specified
{code}
Cause:
{code:none}
hostedcontrolplane controller crashes when hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID is undefined
{code}
Consequence:
{code:none}
control-plane-operator enters a crash loop
{code}
Output:
Cause: "hostedcontrolplane controller crashes when hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID is undefined"
Consequence: "control-plane-operator enters a crash loop"
Objective: Find all GitHub PR URLs associated with this bug.
Sources to check (in priority order):
Remote Links (Primary source - web links in Jira):
remotelinks, or issuelinks with outward GitHub PR linkshttps://github\.com/[\w-]+/[\w-]+/pull/\d+gh issue view {JIRA-KEY} - Jira keys are NOT GitHub issue numbersBug Description:
description field for GitHub PR URLshttps://github\.com/([\w-]+)/([\w-]+)/pull/(\d+)Bug Comments:
comment.comments arraybody field for GitHub PR URLsSearch by bug number (Fallback if no PR URLs found):
for repo in "openshift/hypershift" "openshift/cluster-api-provider-aws" "openshift/origin"; do
gh pr list --repo "$repo" --search "{issue-key} in:title,body" --state all --limit 10 --json number,url,title
done
Found PRs mentioning {issue-key}:
1. openshift/hypershift#4567 - Fix panic when CloudProviderConfig.Subnet is undefined
2. openshift/hypershift#4568 - Add tests for Subnet validation
Which PRs should be included in the release note? (enter numbers separated by commas, or 'all')
gh issue view {JIRA-KEY} - this will failURL Parsing:
For each found URL https://github.com/openshift/hypershift/pull/4567:
org: "openshift"repo: "hypershift"pr_number: "4567"{"url": "...", "repo": "openshift/hypershift", "number": "4567"}Deduplication:
Validation:
No GitHub PRs found linked to {issue-key}.
Please link at least one PR to generate release notes.
How to link PRs in Jira:
1. Edit the bug in Jira
2. Add a web link to the GitHub PR URL
3. Or mention the PR URL in a comment
4. Then run this command again
Exit without updating the ticket.Example:
Found PRs:
[
{
"url": "https://github.com/openshift/hypershift/pull/4567",
"repo": "openshift/hypershift",
"number": "4567"
},
{
"url": "https://github.com/openshift/hypershift/pull/4568",
"repo": "openshift/hypershift",
"number": "4568"
}
]
Objective: Extract Fix, Result, and Workaround information from each linked PR.
For each PR in the list:
Command:
gh pr view {number} --json body,title,commits,url,state --repo {repo}
Error handling:
if ! gh pr view {number} --json body,title,commits,url,state --repo {repo} 2>/dev/null; then
echo "Warning: Unable to access PR {url}"
echo "Verify the PR exists and you have permissions."
# Skip this PR, continue with next
fi
Expected output (JSON):
{
"body": "This PR fixes the panic when CloudProviderConfig.Subnet is not specified...",
"title": "Fix panic when CloudProviderConfig.Subnet is not specified",
"commits": [
{
"messageHeadline": "Add nil check for Subnet field",
"messageBody": "This prevents the controller from crashing..."
}
],
"url": "https://github.com/openshift/hypershift/pull/4567",
"state": "MERGED"
}
Parse and store:
title: PR title (short summary)body: Full PR descriptioncommits: Array of commit objects with messagesstate: PR state (MERGED, OPEN, CLOSED)Command:
gh pr diff {number} --repo {repo}
Purpose: Understand what code was actually changed
Analysis strategy:
+)if err != nil)if x == nil)Example diff analysis:
+if hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet == nil {
+ return fmt.Errorf("Subnet configuration is required")
+}
Summary: "Added nil check for CloudProviderConfig.Subnet field"
Command:
gh pr view {number} --json comments --repo {repo}
Expected output (JSON):
{
"comments": [
{
"author": {"login": "reviewer1"},
"body": "This looks good. The nil check will prevent the crash."
},
{
"author": {"login": "author"},
"body": "Yes, and I also added a more descriptive error message."
}
]
}
Analysis strategy:
Combine all sources (title, body, commits, diff, comments) to extract:
Fix (what was changed):
Example Fix:
Added nil check for CloudProviderConfig.Subnet before accessing Subnet.ID field to prevent nil pointer dereference
Result (outcome after the fix):
Example Result:
The control-plane-operator no longer crashes when CloudProviderConfig.Subnet is not specified
Workaround (temporary solution before fix):
Example Workaround (if found):
Users can manually specify a Subnet value in the HostedCluster spec to avoid the crash
Objective: If multiple PRs are linked, synthesize them into a single coherent release note.
Scenarios:
Example:
Strategy: Combine all fixes into a narrative
Fix: Added nil check for CloudProviderConfig.Subnet field (PR #123), improved error messaging for missing configuration (PR #456), and added validation tests to prevent regression (PR #789)
Example:
Strategy: Mention the fix once, note the backports
Fix: Added nil check for CloudProviderConfig.Subnet field (backported to 4.20 and 4.19)
Example:
Strategy: Analyze the code diffs to determine what actually happened, or ask user:
Found multiple PRs with different fix descriptions:
- PR #123: "Fixed by adding validation"
- PR #456: "Fixed by removing the field access"
Which description is more accurate, or should I combine them?
Objective: Create the final release note text following the standard template.
Template:
Cause: {cause from Jira}
Consequence: {consequence from Jira}
Fix: {synthesized from PRs}
Result: {synthesized from PRs}
Workaround: {synthesized from PRs - optional}
Formatting rules:
Example output:
Cause: hostedcontrolplane controller crashes when hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID is undefined
Consequence: control-plane-operator enters a crash loop
Fix: Added nil check for CloudProviderConfig.Subnet before accessing Subnet.ID field
Result: The control-plane-operator no longer crashes when CloudProviderConfig.Subnet is not specified
Objective: Scan the release note text for sensitive data before submission.
Patterns to detect:
API Tokens and Keys:
(sk|pk)_[a-zA-Z0-9]{20,}ghp_[a-zA-Z0-9]{36}gho_[a-zA-Z0-9]{36}github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}AWS Credentials:
AKIA[0-9A-Z]{16}aws_access_key_id\s*=\s*[A-Z0-9]+aws_secret_access_key\s*=\s*[A-Za-z0-9/+=]+Passwords in URLs:
https?://[^:]+:[^@]+@https://user:password@example.comJWT Tokens:
eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+SSH Private Keys:
-----BEGIN (RSA|OPENSSH|DSA|EC|PGP) PRIVATE KEY-----Kubernetes Secrets:
[a-zA-Z0-9+/]{40,}==? (base64 encoded secrets)Validation logic:
sensitive_patterns = {
"API Token": r"(sk|pk)_[a-zA-Z0-9]{20,}",
"GitHub Token": r"gh[po]_[a-zA-Z0-9]{36}",
"AWS Access Key": r"AKIA[0-9A-Z]{16}",
"URL with credentials": r"https?://[^:]+:[^@]+@",
"JWT Token": r"eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+",
"Private Key": r"-----BEGIN .* PRIVATE KEY-----"
}
for name, pattern in sensitive_patterns.items():
if re.search(pattern, release_note_text):
print(f"Security validation failed!")
print(f"Detected what appears to be {name} in the release note text.")
print(f"Please review the source PRs and remove any credentials.")
exit(1)
If validation fails:
Security validation failed!
Detected what appears to be an API token in the release note text.
This may have come from:
- PR description
- Commit messages
- Code changes (diff)
- PR comments
Please review the source PRs and remove any credentials before proceeding.
Use placeholder values instead:
- YOUR_API_KEY
- <redacted>
- ********
Aborting release note creation.
Objective: Determine the appropriate Release Note Type for this bug.
Available types (from Jira dropdown):
Auto-detection strategy:
For OCPBUGS: Default suggestion is "Bug Fix" (most common)
Check for CVE references:
Check for deprecation:
Check for new features:
Check for known issues:
User interaction:
Use the AskUserQuestion tool:
questions = [{
"question": "What type of release note is this?",
"header": "Type",
"multiSelect": false,
"options": [
{
"label": "Bug Fix",
"description": "Fix for a defect (most common)"
},
{
"label": "Known Issue",
"description": "Documents a known problem without a fix"
},
{
"label": "Enhancement",
"description": "New feature or improvement"
},
{
"label": "CVE",
"description": "Security vulnerability fix"
}
]
}]
Store selection for use in the next step.
Objective: Write the release note to the Jira ticket.
MCP tool call:
mcp__atlassian__jira_update_issue(
issue_key=<issue-key>,
fields={
"customfield_12320850": {"value": "<selected_type>"},
"customfield_12317313": "<formatted_release_note_text>"
}
)
Field details:
customfield_12320850: Release Note Type (must be exact match from dropdown)customfield_12317313: Release Note Text (plain text)Error handling:
Permission denied:
Failed to update {issue-key}.
Error: You do not have permission to edit Release Note fields
Please contact your Jira administrator or manually add the release note.
Generated release note (for manual entry):
---
{release_note_text}
---
Invalid field value:
Failed to update Release Note Type field.
Error: Value "{selected_type}" is not valid
Please select a different type or manually update in Jira.
Field not found:
Failed to update {issue-key}.
Error: Field customfield_12320850 not found
This may indicate a different Jira instance or configuration.
Please manually add the release note.
Success response:
{
"success": true,
"issue": {
"key": "OCPBUGS-38358",
"fields": {
"customfield_12320850": {"value": "Bug Fix"},
"customfield_12317313": "Cause: ... Consequence: ... Fix: ... Result: ..."
}
}
}
Objective: Show the user what was created and provide next steps.
Output format:
✓ Release Note Created for {issue-key}
Type: {Release Note Type}
Text:
---
{Release Note Text with proper formatting}
---
Updated: https://issues.redhat.com/browse/{issue-key}
Next steps:
- Review the release note in Jira
- Edit manually if any adjustments are needed
- The release note will be included in the next release
Example:
✓ Release Note Created for OCPBUGS-38358
Type: Bug Fix
Text:
---
Cause: hostedcontrolplane controller crashes when hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID is undefined
Consequence: control-plane-operator enters a crash loop
Fix: Added nil check for CloudProviderConfig.Subnet before accessing Subnet.ID field
Result: The control-plane-operator no longer crashes when CloudProviderConfig.Subnet is not specified
---
Updated: https://issues.redhat.com/browse/OCPBUGS-38358
Next steps:
- Review the release note in Jira
- Edit manually if any adjustments are needed
- The release note will be included in the next release
Problem: Some PRs can't be accessed or analyzed
Recovery:
Analyzed 2 of 3 linked PRs:
✓ PR #123
✓ PR #456
✗ PR #789 (access denied)
Problem: Missing Cause or Consequence sections
Recovery:
Problem: PRs don't clearly explain the fix
Recovery:
The linked PR doesn't clearly describe the fix.
Based on code analysis, it appears to:
{best guess from diff}
Is this correct? If not, please describe the fix:
Problem: Multiple PRs describe different fixes
Recovery: