Initial commit
This commit is contained in:
808
skills/create-release-note/SKILL.md
Normal file
808
skills/create-release-note/SKILL.md
Normal file
@@ -0,0 +1,808 @@
|
||||
---
|
||||
name: Create Release Note
|
||||
description: Detailed implementation guide for generating bug fix release notes from Jira and GitHub PRs
|
||||
---
|
||||
|
||||
# Create Release Note
|
||||
|
||||
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.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
This skill is automatically invoked by the `/jira:create-release-note` command and should not be called directly by users.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- MCP Jira server configured and accessible
|
||||
- GitHub CLI (`gh`) installed and authenticated
|
||||
- User has read access to the Jira bug
|
||||
- User has write access to Release Note fields in Jira
|
||||
- User has read access to linked GitHub repositories
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Fetch and Validate Jira Bug
|
||||
|
||||
**Objective**: Retrieve the bug ticket and validate it's appropriate for release note generation.
|
||||
|
||||
**Actions**:
|
||||
|
||||
1. **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"
|
||||
)
|
||||
```
|
||||
|
||||
2. **Parse the response**:
|
||||
- Extract `issuetype.name` - verify it's "Bug"
|
||||
- Extract `description` - full bug description text
|
||||
- Extract `issuelinks` - array of linked issues
|
||||
- Extract `customfield_12320850` - current Release Note Type (if already set)
|
||||
- Extract `customfield_12317313` - current Release Note Text (if already set)
|
||||
- Extract `comment.comments` - array of comment objects
|
||||
|
||||
3. **Validate issue type**:
|
||||
- If `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)
|
||||
```
|
||||
- If user says no, exit gracefully
|
||||
|
||||
4. **Check if release note already exists**:
|
||||
- If `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)
|
||||
```
|
||||
- If user says no, exit gracefully
|
||||
|
||||
### Step 2: Parse Bug Description for Cause and Consequence
|
||||
|
||||
**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**:
|
||||
|
||||
1. **Look for "Cause:" section**:
|
||||
- Search for the string "Cause:" (case-insensitive)
|
||||
- Extract text between "Cause:" and the next major section
|
||||
- Remove Jira markup: `{code:none}`, `{code}`, etc.
|
||||
- Trim whitespace
|
||||
|
||||
2. **Look for "Consequence:" section**:
|
||||
- Search for the string "Consequence:" (case-insensitive)
|
||||
- Extract text between "Consequence:" and the next major section
|
||||
- Remove Jira markup
|
||||
- Trim whitespace
|
||||
|
||||
3. **Alternative patterns**:
|
||||
- Some bugs may use "Root Cause:" instead of "Cause:"
|
||||
- Some bugs may use "Impact:" instead of "Consequence:"
|
||||
- Try variations if exact match not found
|
||||
|
||||
4. **Handle missing sections**:
|
||||
- If Cause is missing:
|
||||
```
|
||||
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
|
||||
```
|
||||
- If Consequence is missing:
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
5. **Interactive input** (if user chooses option 1):
|
||||
- Prompt: "What is the root cause of this bug?"
|
||||
- Collect user input
|
||||
- Use as Cause value
|
||||
- Repeat for Consequence if needed
|
||||
|
||||
**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"
|
||||
```
|
||||
|
||||
### Step 3: Extract Linked GitHub PRs
|
||||
|
||||
**Objective**: Find all GitHub PR URLs associated with this bug.
|
||||
|
||||
**Sources to check** (in priority order):
|
||||
|
||||
1. **Remote Links** (Primary source - web links in Jira):
|
||||
- Check the Jira issue response for web links
|
||||
- Field name varies: `remotelinks`, or `issuelinks` with outward GitHub PR links
|
||||
- Extract GitHub PR URLs matching pattern: `https://github\.com/[\w-]+/[\w-]+/pull/\d+`
|
||||
- **IMPORTANT**: Never use `gh issue view {JIRA-KEY}` - Jira keys are NOT GitHub issue numbers
|
||||
|
||||
2. **Bug Description**:
|
||||
- Scan the `description` field for GitHub PR URLs
|
||||
- Use regex: `https://github\.com/([\w-]+)/([\w-]+)/pull/(\d+)`
|
||||
- Extract and parse all matches
|
||||
- **IMPORTANT**: Only extract full PR URLs, not issue references
|
||||
|
||||
3. **Bug Comments**:
|
||||
- Iterate through `comment.comments` array
|
||||
- For each comment, scan `body` field for GitHub PR URLs
|
||||
- Use same regex pattern
|
||||
- Extract all matches
|
||||
|
||||
4. **Search by bug number** (Fallback if no PR URLs found):
|
||||
- If no PRs found via links, search GitHub for PRs mentioning the bug
|
||||
- **For OCPBUGS**: Try common OpenShift repos:
|
||||
```bash
|
||||
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
|
||||
```
|
||||
- Display found PRs and ask user to confirm which are relevant:
|
||||
```
|
||||
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')
|
||||
```
|
||||
- **IMPORTANT**: Never use `gh issue view {JIRA-KEY}` - this will fail
|
||||
|
||||
**URL Parsing**:
|
||||
|
||||
For each found URL `https://github.com/openshift/hypershift/pull/4567`:
|
||||
- Extract `org`: "openshift"
|
||||
- Extract `repo`: "hypershift"
|
||||
- Extract `pr_number`: "4567"
|
||||
- Store as: `{"url": "...", "repo": "openshift/hypershift", "number": "4567"}`
|
||||
|
||||
**Deduplication**:
|
||||
|
||||
- Keep only unique PR URLs
|
||||
- If same PR is mentioned multiple times, include it only once
|
||||
|
||||
**Validation**:
|
||||
|
||||
- If no PRs found after all attempts:
|
||||
```
|
||||
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"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Step 4: Analyze Each GitHub PR
|
||||
|
||||
**Objective**: Extract Fix, Result, and Workaround information from each linked PR.
|
||||
|
||||
**For each PR in the list**:
|
||||
|
||||
#### 4.1: Fetch PR Details
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
gh pr view {number} --json body,title,commits,url,state --repo {repo}
|
||||
```
|
||||
|
||||
**Error handling**:
|
||||
```bash
|
||||
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):
|
||||
```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 description
|
||||
- `commits`: Array of commit objects with messages
|
||||
- `state`: PR state (MERGED, OPEN, CLOSED)
|
||||
|
||||
#### 4.2: Fetch PR Diff
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
gh pr diff {number} --repo {repo}
|
||||
```
|
||||
|
||||
**Purpose**: Understand what code was actually changed
|
||||
|
||||
**Analysis strategy**:
|
||||
- Look for added lines (starting with `+`)
|
||||
- Identify key changes:
|
||||
- New error handling (`if err != nil`)
|
||||
- New validation checks (`if x == nil`)
|
||||
- New return statements
|
||||
- New error messages
|
||||
- Don't include the entire diff in the release note
|
||||
- Summarize the nature of changes
|
||||
|
||||
**Example diff analysis**:
|
||||
```diff
|
||||
+if hcp.Spec.Platform.AWS.CloudProviderConfig.Subnet == nil {
|
||||
+ return fmt.Errorf("Subnet configuration is required")
|
||||
+}
|
||||
```
|
||||
|
||||
**Summary**: "Added nil check for CloudProviderConfig.Subnet field"
|
||||
|
||||
#### 4.3: Fetch PR Comments
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
gh pr view {number} --json comments --repo {repo}
|
||||
```
|
||||
|
||||
**Expected output** (JSON):
|
||||
```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**:
|
||||
- Look for mentions of:
|
||||
- "workaround"
|
||||
- "temporary fix"
|
||||
- "until this is merged"
|
||||
- "users can work around this by..."
|
||||
- Extract workaround information if found
|
||||
- Look for clarifications about the fix
|
||||
- Ignore unrelated discussion
|
||||
|
||||
#### 4.4: Synthesize PR Analysis
|
||||
|
||||
**Combine all sources** (title, body, commits, diff, comments) to extract:
|
||||
|
||||
**Fix** (what was changed):
|
||||
- Prefer: PR body description of the fix
|
||||
- Fallback: PR title + commit message summaries
|
||||
- Focus on: What code/configuration was modified
|
||||
- Keep concise: 1-3 sentences
|
||||
- Avoid: Implementation details (specific function names, line numbers)
|
||||
|
||||
**Example Fix**:
|
||||
```
|
||||
Added nil check for CloudProviderConfig.Subnet before accessing Subnet.ID field to prevent nil pointer dereference
|
||||
```
|
||||
|
||||
**Result** (outcome after the fix):
|
||||
- Prefer: PR body description of expected behavior
|
||||
- Fallback: Inverse of the bug's "Actual results"
|
||||
- Focus on: What changed for users
|
||||
- Keep concise: 1-2 sentences
|
||||
|
||||
**Example Result**:
|
||||
```
|
||||
The control-plane-operator no longer crashes when CloudProviderConfig.Subnet is not specified
|
||||
```
|
||||
|
||||
**Workaround** (temporary solution before fix):
|
||||
- Only include if explicitly mentioned in PR or comments
|
||||
- Look for keywords: "workaround", "temporary", "manually"
|
||||
- If not found: Omit this section entirely
|
||||
|
||||
**Example Workaround** (if found):
|
||||
```
|
||||
Users can manually specify a Subnet value in the HostedCluster spec to avoid the crash
|
||||
```
|
||||
|
||||
### Step 5: Combine Multiple PRs
|
||||
|
||||
**Objective**: If multiple PRs are linked, synthesize them into a single coherent release note.
|
||||
|
||||
**Scenarios**:
|
||||
|
||||
#### Scenario A: Multiple PRs with different fixes
|
||||
|
||||
Example:
|
||||
- PR #123: Fixes nil pointer crash
|
||||
- PR #456: Adds better error message
|
||||
- PR #789: Adds validation tests
|
||||
|
||||
**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)
|
||||
```
|
||||
|
||||
#### Scenario B: Multiple PRs for same fix (backports)
|
||||
|
||||
Example:
|
||||
- PR #123: Fix for main branch
|
||||
- PR #456: Backport to release-4.20
|
||||
- PR #789: Backport to release-4.19
|
||||
|
||||
**Strategy**: Mention the fix once, note the backports
|
||||
```
|
||||
Fix: Added nil check for CloudProviderConfig.Subnet field (backported to 4.20 and 4.19)
|
||||
```
|
||||
|
||||
#### Scenario C: Multiple PRs with conflicting descriptions
|
||||
|
||||
Example:
|
||||
- PR #123 says: "Fixed by adding validation"
|
||||
- PR #456 says: "Fixed by removing the field access"
|
||||
|
||||
**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?
|
||||
```
|
||||
|
||||
### Step 6: Format Release Note
|
||||
|
||||
**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**:
|
||||
- Each line starts with the field name followed by a colon and space
|
||||
- No blank lines between fields
|
||||
- Workaround field is optional - omit if no workaround exists
|
||||
- Keep each field concise but complete
|
||||
- Use proper capitalization and punctuation
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
### Step 7: Security Validation
|
||||
|
||||
**Objective**: Scan the release note text for sensitive data before submission.
|
||||
|
||||
**Patterns to detect**:
|
||||
|
||||
1. **API Tokens and Keys**:
|
||||
- Pattern: `(sk|pk)_[a-zA-Z0-9]{20,}`
|
||||
- Pattern: `ghp_[a-zA-Z0-9]{36}`
|
||||
- Pattern: `gho_[a-zA-Z0-9]{36}`
|
||||
- Pattern: `github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}`
|
||||
|
||||
2. **AWS Credentials**:
|
||||
- Pattern: `AKIA[0-9A-Z]{16}`
|
||||
- Pattern: `aws_access_key_id\s*=\s*[A-Z0-9]+`
|
||||
- Pattern: `aws_secret_access_key\s*=\s*[A-Za-z0-9/+=]+`
|
||||
|
||||
3. **Passwords in URLs**:
|
||||
- Pattern: `https?://[^:]+:[^@]+@`
|
||||
- Example: `https://user:password@example.com`
|
||||
|
||||
4. **JWT Tokens**:
|
||||
- Pattern: `eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+`
|
||||
|
||||
5. **SSH Private Keys**:
|
||||
- Pattern: `-----BEGIN (RSA|OPENSSH|DSA|EC|PGP) PRIVATE KEY-----`
|
||||
|
||||
6. **Kubernetes Secrets**:
|
||||
- Pattern: `[a-zA-Z0-9+/]{40,}==?` (base64 encoded secrets)
|
||||
- Context: If appears after "token:", "secret:", "password:"
|
||||
|
||||
**Validation logic**:
|
||||
|
||||
```python
|
||||
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.
|
||||
```
|
||||
|
||||
### Step 8: Select Release Note Type
|
||||
|
||||
**Objective**: Determine the appropriate Release Note Type for this bug.
|
||||
|
||||
**Available types** (from Jira dropdown):
|
||||
1. Bug Fix
|
||||
2. Release Note Not Required
|
||||
3. Known Issue
|
||||
4. Enhancement
|
||||
5. Rebase
|
||||
6. Technology Preview
|
||||
7. Deprecated Functionality
|
||||
8. CVE
|
||||
|
||||
**Auto-detection strategy**:
|
||||
|
||||
1. **For OCPBUGS**: Default suggestion is "Bug Fix" (most common)
|
||||
|
||||
2. **Check for CVE references**:
|
||||
- If bug description or PRs mention "CVE-" → Suggest "CVE"
|
||||
|
||||
3. **Check for deprecation**:
|
||||
- If PRs mention "deprecated", "deprecating", "removing" → Suggest "Deprecated Functionality"
|
||||
|
||||
4. **Check for new features**:
|
||||
- If PRs add significant new functionality → Suggest "Enhancement"
|
||||
- Though typically bugs should be "Bug Fix"
|
||||
|
||||
5. **Check for known issues**:
|
||||
- If PRs don't actually fix the issue, just document it → Suggest "Known Issue"
|
||||
|
||||
**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.
|
||||
|
||||
### Step 9: Update Jira Ticket
|
||||
|
||||
**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**:
|
||||
|
||||
1. **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}
|
||||
---
|
||||
```
|
||||
|
||||
2. **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.
|
||||
```
|
||||
|
||||
3. **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: ..."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 10: Display Results
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
## Error Recovery Strategies
|
||||
|
||||
### PR Analysis Failures
|
||||
|
||||
**Problem**: Some PRs can't be accessed or analyzed
|
||||
|
||||
**Recovery**:
|
||||
1. Log warning for each failed PR
|
||||
2. Continue with successfully analyzed PRs
|
||||
3. If all PRs fail, treat as "No PRs linked" error
|
||||
4. Show summary of what was analyzed:
|
||||
```
|
||||
Analyzed 2 of 3 linked PRs:
|
||||
✓ PR #123
|
||||
✓ PR #456
|
||||
✗ PR #789 (access denied)
|
||||
```
|
||||
|
||||
### Incomplete Bug Description
|
||||
|
||||
**Problem**: Missing Cause or Consequence sections
|
||||
|
||||
**Recovery**:
|
||||
1. Offer interactive input option
|
||||
2. Provide template for user
|
||||
3. Allow user to update bug and retry
|
||||
4. Don't proceed without both fields
|
||||
|
||||
### Ambiguous PR Content
|
||||
|
||||
**Problem**: PRs don't clearly explain the fix
|
||||
|
||||
**Recovery**:
|
||||
1. Use PR title as fallback
|
||||
2. Analyze code diff more carefully
|
||||
3. Ask user for clarification:
|
||||
```
|
||||
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:
|
||||
```
|
||||
|
||||
### Conflicting Information
|
||||
|
||||
**Problem**: Multiple PRs describe different fixes
|
||||
|
||||
**Recovery**:
|
||||
1. Present both descriptions to user
|
||||
2. Ask which is correct or how to combine
|
||||
3. Use AI to attempt intelligent synthesis
|
||||
4. If synthesis fails, escalate to user
|
||||
|
||||
## Best Practices for Implementation
|
||||
|
||||
1. **Always validate inputs**: Check that issue exists, PRs are accessible, fields are present
|
||||
2. **Fail gracefully**: Provide helpful error messages with recovery instructions
|
||||
3. **Be defensive**: Handle missing data, API errors, permission issues
|
||||
4. **Log progress**: Show user what's happening at each step
|
||||
5. **Preserve data**: If update fails, show generated content so it's not lost
|
||||
6. **Security first**: Always validate before updating Jira
|
||||
7. **User in control**: Confirm selections, allow overrides
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Bug with single linked PR
|
||||
- [ ] Bug with multiple linked PRs
|
||||
- [ ] Bug with no linked PRs (error case)
|
||||
- [ ] Bug with inaccessible PR (warning case)
|
||||
- [ ] Bug missing Cause section (error case)
|
||||
- [ ] Bug missing Consequence section (error case)
|
||||
- [ ] Bug with existing release note (warning case)
|
||||
- [ ] Bug that's not a Bug type (warning case)
|
||||
- [ ] Release note with detected credentials (security failure)
|
||||
- [ ] Different Release Note Type selections
|
||||
- [ ] Update permission denied (error case)
|
||||
- [ ] MCP server not configured (error case)
|
||||
- [ ] gh CLI not authenticated (error case)
|
||||
Reference in New Issue
Block a user