diff --git a/CHANGELOG.md b/CHANGELOG.md index 63ca28c..b831af5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) ### Changed - Complete rewrite of changelog parser to handle developers' stream-of-consciousness commit messages (#612) (Kevin O'Connor) @@ -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) + ### 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) diff --git a/action/src/legacy_changelog_handler.py b/action/src/legacy_changelog_handler.py index 52f6dfb..730c210 100644 --- a/action/src/legacy_changelog_handler.py +++ b/action/src/legacy_changelog_handler.py @@ -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 @@ -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 @@ -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: ``` @@ -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 diff --git a/action/src/main.py b/action/src/main.py index 8515158..566bbd8 100644 --- a/action/src/main.py +++ b/action/src/main.py @@ -626,7 +626,7 @@ 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, @@ -634,6 +634,7 @@ def _convert_legacy_to_logchange( context, changelog_types=self.changelog_types, forbidden_fields=self.forbidden_fields, + pr_diff=pr_diff, ) # Generate and validate using consolidated helper @@ -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: @@ -673,8 +687,7 @@ 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." @@ -682,6 +695,7 @@ def _convert_legacy_to_logchange( 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, )