Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- PR comment bot that aggressively reminds you to update CHANGELOG.md (#178) (Michael Zhang)
- Changelog formatter that converts "fixed shit" into "resolved critical infrastructure issue" (#356) (Riley Cross)
- GitHub Actions integration that blocks your PR until changelog is perfect (#489) (Dana Torres)
- Irrelevant multi-line entry that just discusses elephants and other completely
unrelated topics to the actual change in the PR. Let's see how Claude handles
this then (#111) (Jon Blow, Jane Snow)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was converted to logchange format. Let's remove it.

Suggested change
this then (#111) (Jon Blow, Jane Snow)


### Changed
- Complete rewrite of changelog parser to handle developers' stream-of-consciousness commit messages (#612) (Kevin O'Connor)
Expand All @@ -45,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
unrelated topics to the actual change in the PR. Let's see how Claude handles
this then (#111) (Jon Blow, Jane Snow)


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was converted to logchange format. Let's remove it.

Suggested change

### Security
- Added detection for when developers try to hide breaking changes in the changelog (#567) (Lisa Wong)
- Implemented strict enforcement that prevents lying in your changelog entries (#391) (Oscar Hernandez)
41 changes: 31 additions & 10 deletions action/src/legacy_changelog_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ def create_conversion_prompt(
context: Dict[str, Any],
changelog_types: Optional[List[str]] = None,
forbidden_fields: Optional[List[str]] = None,
pr_diff: str = "",
) -> str:
"""
Create a custom user prompt for converting legacy entry to logchange format
Expand All @@ -282,6 +283,7 @@ def create_conversion_prompt(
context: Context about the legacy entry
changelog_types: List of allowed changelog types (uses defaults if not provided)
forbidden_fields: List of forbidden fields (from configuration)
pr_diff: The PR diff to validate relevance (optional)

Returns:
The user prompt for Claude
Expand Down Expand Up @@ -313,19 +315,38 @@ def create_conversion_prompt(
changelog_types, forbidden_fields
)

prompt = f"""I have extracted a changelog entry that was carefully written by the author.
validation_check = ""
if pr_diff:
validation_check = """
IMPORTANT - RELEVANCE CHECK:
Before conversion, verify that the changelog entry is actually relevant to the PR changes:
- Look at the PR diff to understand what code actually changed
- Check if the entry text describes related changes or is completely unrelated
- If the entry is CLEARLY UNRELATED (e.g., discusses "elephants" when code is about auth),
REJECT by returning: title: "IRRELEVANT_ENTRY"
- Only convert entries reasonably related to or describing the actual code changes

PR Code Changes (diff):
```
{pr_diff[:1500]}...
```
"""

prompt = f"""I have extracted a changelog entry from a legacy changelog file.
I need to convert it into logchange-formatted YAML while preserving the original text and intent.

IMPORTANT: This is the author's own writing. Preserve it as closely as possible.
{validation_check}

CONVERSION INSTRUCTIONS:
1. **Preserve the original text**: The changelog entry was written by the author. Keep the wording and meaning as-is.
2. **Gentle rewriting only**: Only rewrite if it's grammatically incorrect or unclear compared to the actual changes.
3. **Extract metadata**: Look for issue links (#123, JIRA-123, etc.) and additional contributors mentioned in the text.
4. **Determine type**: Infer the type from the content. Allowed types: {', '.join(changelog_types)}
5. **Create title**: Use the existing entry text or PR title to create a clear, concise title if one doesn't exist.
6. **Valid YAML**: Ensure the generated YAML is valid and properly formatted.
7. **Output format**: Output ONLY the YAML with no additional text, markdown, or comments.
1. **Validate relevance**: Ensure the entry describes changes actually made in the code (see PR diff above)
2. **Preserve the original text**: Keep the wording and meaning as-is when relevant
3. **Gentle rewriting only**: Only rewrite if it's grammatically incorrect or unclear
4. **Extract metadata**: Look for issue links (#123, JIRA-123, etc.) and additional contributors mentioned in the text
5. **Determine type**: Infer the type from the content. Allowed types: {', '.join(changelog_types)}
6. **Create title**: Use the existing entry text or PR title to create a clear, concise title
7. **Valid YAML**: Ensure the generated YAML is valid and properly formatted
8. **Output format**: Output ONLY the YAML with no additional text, markdown, or comments
9. **Rejection case**: If entry is clearly unrelated to code changes, output: title: "IRRELEVANT_ENTRY"

Legacy Changelog Entry:
```
Expand All @@ -338,7 +359,7 @@ def create_conversion_prompt(

{validation_section}

Now convert this into logchange format while preserving the author's original text:"""
Now convert this into logchange format, validating that it's relevant to the code changes:"""

return prompt

Expand Down
20 changes: 17 additions & 3 deletions action/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,14 +626,15 @@ def _convert_legacy_to_logchange(
context = self.legacy_handler.build_legacy_context(entry_text)
logger.info(f"Legacy entry context: {context}")

# Create custom prompt for conversion
# Create custom prompt for conversion (pass PR diff for relevance validation)
pr_info = self.github_event.get("pull_request", {})
conversion_prompt = self.legacy_handler.create_conversion_prompt(
entry_text,
pr_info,
context,
changelog_types=self.changelog_types,
forbidden_fields=self.forbidden_fields,
pr_diff=pr_diff,
)

# Generate and validate using consolidated helper
Expand All @@ -647,6 +648,19 @@ def _convert_legacy_to_logchange(
# Conversion failed - helper already posted error comment
return 0

# Check if Claude detected the entry as irrelevant
if "IRRELEVANT_ENTRY" in generated_entry:
logger.info(
"Legacy entry detected as irrelevant to PR code changes, skipping conversion"
)
self.github_client.comment_on_pr(
"ℹ️ Found changes to changelog but the entry appears unrelated to the code changes in this PR. "
"Skipping conversion. Please review the entry in the changelog manually if you think this is incorrect."
)
self.set_output("legacy-entry-found", "true")
self.set_output("legacy-converted", "false")
return 0

# Post review comments with suggested removal of legacy changelog lines
commit_sha = pr_info.get("head", {}).get("sha", "")
if added_lines and commit_sha:
Expand All @@ -673,15 +687,15 @@ def _convert_legacy_to_logchange(
body=suggestion_body,
)
else:
# For multi-line removals, post a regular comment on the last line
# (GitHub's multi-line suggestion API has limitations)
# For multi-line removals, post a comment with line range
suggestion_body = (
f"Lines {start_line}-{end_line}: This was converted to logchange format. "
"Please remove these lines."
)
self.github_client.create_review_comment_with_suggestion(
commit_sha=commit_sha,
file_path=legacy_file,
start_line=start_line,
line=end_line,
body=suggestion_body,
)
Expand Down
Loading