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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,15 @@ Introduces improved changelog management with a dedicated marker system for auto
### Technical Details
- Refactored changelog generation logic for better maintainability
- Improved marker-based insertion system for more reliable updates


## [1.1.1] - August 2025

Improves the changelog comparison logic to ensure more accurate change detection by comparing against the working directory instead of HEAD, enhancing reliability of the changelog management process.

### Fixed
- Enhanced changelog comparison accuracy by using working directory state instead of HEAD reference

### Technical Details
- Updated internal comparison logic for more reliable changelog state detection
<!-- Updated for AI processing at 2025-08-17T21:37:53.855Z -->
107 changes: 50 additions & 57 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -287,23 +287,19 @@ runs:

// Create placeholder content if no existing content found
if (!existingContent) {
existingContent = '# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n<!-- CONTEXT_LEDGER_MARKER -->\n';
existingContent = '# Changelog\n\n## [Unreleased]\n- Placeholder for AI-generated changelog\n\n<!-- AI_APPEND_HERE -->\n';
}

// Ensure Context Ledger marker exists
if (!existingContent.includes('<!-- CONTEXT_LEDGER_MARKER -->')) {
existingContent = existingContent.trimEnd() + '\n\n<!-- CONTEXT_LEDGER_MARKER -->\n';
console.log('📝 Added Context Ledger marker');
// Ensure AI_APPEND_HERE marker is always present at the end
if (!existingContent.includes('<!-- AI_APPEND_HERE -->')) {
existingContent += '\n\n<!-- AI_APPEND_HERE -->';
console.log('📝 Added AI_APPEND_HERE marker');
}

// If file exists but not in PR diff, add a small change to trigger PR inclusion
// If file exists but not in PR diff, add timestamp to trigger PR inclusion
if (fileExistsOnTarget) {
// Add a timestamp comment before the marker to ensure it shows in diff
const timestamp = new Date().toISOString();
existingContent = existingContent.replace(
'<!-- CONTEXT_LEDGER_MARKER -->',
`<!-- Updated: ${timestamp} -->\n<!-- CONTEXT_LEDGER_MARKER -->`
);
existingContent += `\n<!-- Updated for AI processing at ${timestamp} -->\n`;
console.log('📝 Adding timestamp to trigger PR diff inclusion');
}

Expand Down Expand Up @@ -453,24 +449,27 @@ runs:
echo "EOF" >> $GITHUB_OUTPUT
fi

# For PRs, check if we should create suggestions
# For PRs, compare against the base branch
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "Fetching base branch for comparison..."
BASE_BRANCH="${{ steps.analyze-changes.outputs.base_branch }}"
git fetch origin "$BASE_BRANCH"

echo "Checking for non-changelog changes in PR..."
# Get all changed files excluding changelog
NON_CHANGELOG_CHANGES=$(git diff --name-only "origin/$BASE_BRANCH..HEAD" | grep -v -E "(CHANGELOG\.md|.*CHANGELOG\.md)$" || true)

if [ -n "$NON_CHANGELOG_CHANGES" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "DEBUG: PR has non-changelog changes, suggestions should be created"
echo "Non-changelog files changed:"
echo "$NON_CHANGELOG_CHANGES"
else
echo "Comparing with origin/$BASE_BRANCH..."
# First, get the content from the base branch
BASE_CONTENT=$(git show "origin/$BASE_BRANCH:${{ inputs.changelog_path }}" 2>/dev/null || echo "")
# Then compare with the current working file
CURRENT_CONTENT=$(cat "${{ inputs.changelog_path }}" 2>/dev/null || echo "")

if [ "$BASE_CONTENT" = "$CURRENT_CONTENT" ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "DEBUG: PR only has changelog changes, skipping suggestions"
echo "DEBUG: No differences from base branch"
else
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "DEBUG: Changelog differs from base branch"
echo "Diff preview:"
# Show the diff between base branch and working directory
git show "origin/$BASE_BRANCH:${{ inputs.changelog_path }}" | diff -u - "${{ inputs.changelog_path }}" || true
fi
else
# For non-PR events, check local changes
Expand Down Expand Up @@ -508,11 +507,6 @@ runs:
git push

- name: Create GitHub PR suggestions
# Only create suggestions if:
# - Changelog was generated (status == 'UPDATED')
# - This is a PR event
# - PR has non-changelog changes (has_changes == 'true')
# - User wants suggestions (create_pr_suggestions == 'true')
if: |
steps.check-status.outputs.status == 'UPDATED' &&
github.event_name == 'pull_request' &&
Expand Down Expand Up @@ -560,12 +554,13 @@ runs:
if (changelogFile.status === 'added') {
core.info('Changelog file is newly added - creating file replacement suggestion');

// For new files, append content to existing changelog
let fullNewChangelog = currentChangelog.trimEnd();
if (fullNewChangelog) {
fullNewChangelog += '\n\n';
// For new files, suggest inserting before the AI_APPEND_HERE marker
let fullNewChangelog;
if (currentChangelog.includes('<!-- AI_APPEND_HERE -->')) {
fullNewChangelog = currentChangelog.replace(/<!-- AI_APPEND_HERE -->/, newContent);
} else {
fullNewChangelog = currentChangelog + '\n\n' + newContent;
}
fullNewChangelog += newContent + '\n';

await github.rest.pulls.createReview({
owner: context.repo.owner,
Expand All @@ -589,13 +584,12 @@ runs:
throw new Error('No patch available for modified file');
}

// Parse patch to find a suitable position for the suggestion
// Parse patch to find lines we can target
const patchLines = patch.split('\n');
let bestPosition = null;
let currentPosition = 0;
let lastContextLine = null;

// Find the AI_CONTENT marker or the last added/context line
// Look for the AI_APPEND_HERE marker in the patch
for (let i = 0; i < patchLines.length; i++) {
const line = patchLines[i];
if (line.startsWith('@@')) {
Expand All @@ -606,37 +600,36 @@ runs:
}
} else if (line.startsWith('+')) {
currentPosition++;
if (line.includes('CONTEXT_LEDGER_MARKER')) {
if (line.includes('AI_APPEND_HERE')) {
bestPosition = currentPosition;
break; // Found our marker, stop searching
break;
}
bestPosition = currentPosition; // Keep track of added lines
} else if (line.startsWith(' ')) {
currentPosition++;
if (line.includes('CONTEXT_LEDGER_MARKER')) {
bestPosition = currentPosition;
break; // Found our marker, stop searching
}
lastContextLine = currentPosition; // Track context lines as fallback
}
}

// Use the best position found, or fall back to last context line
if (!bestPosition && lastContextLine) {
bestPosition = lastContextLine;
// If no marker found in patch, find last added line
if (!bestPosition) {
currentPosition = 0;
for (let i = 0; i < patchLines.length; i++) {
const line = patchLines[i];
if (line.startsWith('@@')) {
const match = line.match(/@@ -\d+,?\d* \+(\d+),?\d* @@/);
if (match) {
currentPosition = parseInt(match[1]) - 1;
}
} else if (line.startsWith('+')) {
currentPosition++;
bestPosition = currentPosition; // Keep updating to get the last one
} else if (line.startsWith(' ')) {
currentPosition++;
}
}
}

if (!bestPosition) {
core.warning('Could not find ideal position in diff, attempting to create comment without line suggestion');
// Instead of throwing, create a general PR comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `🤖 **AI Changelog Ready!**\n\nAdd this to your \`${targetPath}\`:\n\n\`\`\`markdown\n${newContent}\n\`\`\`\n\n*Note: Could not create an inline suggestion due to diff limitations. Please copy and paste the above content manually.*`
});
core.info('✅ Posted changelog as PR comment (could not create inline suggestion)');
return;
throw new Error('Could not find suitable position in diff');
}

// Create suggestion targeting the found position
Expand Down