Skip to content

Commit 6af5c2d

Browse files
vaindclaude
andauthored
fix: improve changelog generation for non-tagged commits and edge cases (#115)
* fix: improve changelog generation for non-tagged commits and edge cases - Switch from git clone to GitHub raw API for better performance - Support commit SHAs as OldTag/NewTag parameters - Use diff-based approach for accurate changelog extraction - Handle repositories without existing changelog files - Add proper error handling and cleanup - Improve test coverage for edge cases 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: improve log message for found changelog files * fix: correct PowerShell script exit code handling in get-changelog.ps1 - Restructure script to use result variable instead of early returns - Ensure proper exit handling in try/catch/finally blocks - Fix CI failures caused by exit code 1 from PowerShell script - All tests continue to pass (62/62 tests passing) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: add changelog entry for changelog generation improvements - Add entry for PR #115 to Unreleased section - Addresses Danger bot requirement for changelog updates 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Revert "fix: correct PowerShell script exit code handling in get-changelog.ps1" This reverts commit 445f392. * fix: handle git diff exit codes properly in PowerShell - Add proper error action preference settings to match CI environment - Handle git diff exit code 1 (differences found) as expected behavior - Use explicit exit 0 to ensure clean script termination - Fixes updater-pr-creation CI failures with PSNativeCommandErrorActionPreference 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: improve logging for changelog diff generation and cleanup process * fix: add logging for changelog length in dependency updater action * tmp * fix: clean up logging and return values in changelog scripts * docs: fix changelog link format to match established convention - Use full markdown link format [#115](url) instead of (#115) - Matches existing changelog entry format 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test: restore proper truncation test with valid tag range - Change test range from 1.0.0-2.4.0 (invalid) to 1.60.0-2.32.0 (valid) - Ensure truncation test actually validates the truncation functionality - Range 1.60.0 to 2.32.0 generates >60k characters and triggers truncation - All 11 tests continue to pass 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: address valid review comments for robustness - Fix diff checking logic: use string conversion for proper emptiness check - Fix truncation safety: handle case when no newlines exist in content - Add graceful fallback to direct truncation when LastIndexOf returns -1 - All tests continue to pass (11/11 tests passing) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 054504c commit 6af5c2d

File tree

3 files changed

+266
-112
lines changed

3 files changed

+266
-112
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ To update your existing Danger workflows:
5252
5353
- Updater - Prevent script injection vulnerabilities through workflow inputs ([#98](https://github.com/getsentry/github-workflows/pull/98))
5454
55+
### Fixes
56+
57+
- Improve changelog generation for non-tagged commits and edge cases ([#115](https://github.com/getsentry/github-workflows/pull/115))
58+
5559
## 2.14.1
5660
5761
### Fixes

updater/scripts/get-changelog.ps1

Lines changed: 123 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,122 +5,154 @@ param(
55
)
66

77
Set-StrictMode -Version latest
8+
$PSNativeCommandErrorActionPreference = $true
9+
$ErrorActionPreference = 'Stop'
810

911
$prefix = 'https?://(www\.)?github.com/'
10-
if (-not ($RepoUrl -match "^$prefix"))
11-
{
12-
Write-Warning "Only github.com repositories are currently supported. Given RepoUrl doesn't look like one: $RepoUrl"
12+
if (-not ($RepoUrl -match "^$prefix([^/]+)/([^/]+?)(?:\.git)?/?$")) {
13+
Write-Warning "Only https://github.com repositories are currently supported. Could not parse repository from URL: $RepoUrl"
1314
return
1415
}
1516

17+
$repoOwner = $matches[2]
18+
$repoName = $matches[3]
19+
$apiRepo = "$repoOwner/$repoName"
20+
21+
# Create temporary directory for changelog files
1622
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid())
1723
New-Item -ItemType Directory $tmpDir | Out-Null
1824

19-
try
20-
{
21-
git clone --depth 1 $RepoUrl $tmpDir
25+
# Function to try different changelog filenames
26+
function Get-ChangelogContent {
27+
param($ref, $filePath)
28+
29+
$changelogNames = @('CHANGELOG.md', 'changelog.md', 'CHANGELOG.txt', 'changelog.txt', 'CHANGELOG')
30+
31+
foreach ($name in $changelogNames) {
32+
try {
33+
# Try fetching directly from raw.githubusercontent.com
34+
$rawUrl = "https://raw.githubusercontent.com/$apiRepo/$ref/$name"
35+
$content = Invoke-RestMethod -Uri $rawUrl -Method Get -ErrorAction SilentlyContinue
36+
if ($content) {
37+
Set-Content -Path $filePath -Value $content -Encoding UTF8
38+
Write-Host "Found $name for ref $ref"
39+
return $true
40+
}
41+
} catch {
42+
# Continue to next filename
43+
}
44+
}
45+
return $false
46+
}
47+
48+
try {
49+
Write-Host 'Fetching CHANGELOG files for comparison...'
2250

23-
$file = $(Get-ChildItem -Path $tmpDir | Where-Object { $_.Name -match '^changelog(\.md|\.txt|)$' } )
24-
if ("$file" -eq '')
25-
{
26-
Write-Warning "Couldn't find a changelog"
51+
# Fetch old changelog
52+
$oldChangelogPath = Join-Path $tmpDir 'old-changelog.md'
53+
if (-not (Get-ChangelogContent $OldTag $oldChangelogPath)) {
54+
Write-Warning "Could not find changelog at $OldTag"
2755
return
2856
}
29-
elseif ($file -is [Array])
30-
{
31-
Write-Warning "Multiple changelogs found: $file"
57+
58+
# Fetch new changelog
59+
$newChangelogPath = Join-Path $tmpDir 'new-changelog.md'
60+
if (-not (Get-ChangelogContent $NewTag $newChangelogPath)) {
61+
Write-Warning "Could not find changelog at $NewTag"
3262
return
3363
}
34-
Write-Host "Found changelog: $file"
35-
[string[]]$lines = Get-Content $file
36-
}
37-
finally
38-
{
39-
Write-Host "Removing $tmpDir"
40-
Remove-Item -Recurse -Force -ErrorAction Continue -Path $tmpDir
41-
}
4264

43-
$startIndex = -1
44-
$endIndex = -1
45-
$changelog = ''
46-
for ($i = 0; $i -lt $lines.Count; $i++)
47-
{
48-
$line = $lines[$i]
49-
50-
if ($startIndex -lt 0)
51-
{
52-
if ($line -match "^#+ +v?$NewTag\b")
53-
{
54-
$startIndex = $i
65+
Write-Host "Generating changelog diff between $OldTag and $NewTag..."
66+
67+
# Generate diff using git diff --no-index
68+
# git diff returns exit code 1 when differences are found, which is expected behavior
69+
# We need to handle this properly when PSNativeCommandErrorActionPreference is enabled
70+
$fullDiff = & {
71+
$oldErrorActionPreference = $ErrorActionPreference
72+
$ErrorActionPreference = 'Continue'
73+
try {
74+
git diff --no-index $oldChangelogPath $newChangelogPath
75+
} finally {
76+
$ErrorActionPreference = $oldErrorActionPreference
5577
}
5678
}
57-
elseif ($line -match "^#+ +v?$OldTag\b")
58-
{
59-
$endIndex = $i - 1
60-
break
79+
80+
# The first lines are diff metadata, skip them
81+
$fullDiff = $fullDiff -split "`n" | Select-Object -Skip 4
82+
if ([string]::IsNullOrEmpty("$fullDiff")) {
83+
Write-Host "No differences found between $OldTag and $NewTag"
84+
return
85+
} else {
86+
Write-Host "Successfully created a changelog diff - $($fullDiff.Count) lines"
6187
}
62-
}
6388

64-
# If the changelog doesn't have a section for the oldTag, stop at the first SemVer that's lower than oldTag.
65-
if ($endIndex -lt 0)
66-
{
67-
$endIndex = $lines.Count - 1 # fallback, may be overwritten below
68-
try
69-
{
70-
$semverOldTag = [System.Management.Automation.SemanticVersion]::Parse($OldTag)
71-
for ($i = $startIndex; $i -lt $lines.Count; $i++)
72-
{
73-
$line = $lines[$i]
74-
if ($line -match '^#+ +v?([0-9]+.*)$')
75-
{
76-
try
77-
{
78-
if ($semverOldTag -ge [System.Management.Automation.SemanticVersion]::Parse($matches[1]))
79-
{
80-
$endIndex = $i - 1
89+
# Extract only the added lines (lines starting with + but not ++)
90+
$addedLines = $fullDiff | Where-Object { $_ -match '^[+][^+]*' } | ForEach-Object { $_.Substring(1) }
91+
92+
if ($addedLines.Count -gt 0) {
93+
# Create clean changelog from added lines
94+
$changelog = ($addedLines -join "`n").Trim()
95+
96+
# Apply formatting to clean changelog
97+
if ($changelog.Length -gt 0) {
98+
# Add header
99+
if (-not ($changelog -match '^(##|#) Changelog')) {
100+
$changelog = "## Changelog`n`n$changelog"
101+
}
102+
103+
# Increase header level by one for content (not the main header)
104+
$changelog = $changelog -replace '(^|\n)(#+) ', '$1$2# ' -replace '^### Changelog', '## Changelog'
105+
106+
# Only add details section if there are deletions or modifications (not just additions)
107+
$hasModifications = $fullDiff | Where-Object { $_ -match '^[-]' -and $_ -notmatch '^[-]{3}' }
108+
if ($hasModifications) {
109+
$changelog += "`n`n<details>`n<summary>Full CHANGELOG.md diff</summary>`n`n"
110+
$changelog += '```diff' + "`n"
111+
$changelog += $fullDiff -join "`n"
112+
$changelog += "`n" + '```' + "`n`n</details>"
113+
}
114+
115+
# Apply standard formatting
116+
# Remove at-mentions.
117+
$changelog = $changelog -replace '@', ''
118+
# Make PR/issue references into links to the original repository (unless they already are links).
119+
$changelog = $changelog -replace '(?<!\[)#([0-9]+)(?![\]0-9])', ('[#$1](' + $RepoUrl + '/issues/$1)')
120+
# Replace any links pointing to github.com so that the target PRs/Issues don't get na notification.
121+
$changelog = $changelog -replace ('\(' + $prefix), '(https://github-redirect.dependabot.com/'
122+
123+
# Limit the changelog length to ~60k to allow for other text in the PR body (total PR limit is 65536 characters).
124+
$limit = 60000
125+
if ($changelog.Length -gt $limit) {
126+
$oldLength = $changelog.Length
127+
Write-Warning "Truncating changelog because it's $($changelog.Length - $limit) characters longer than the limit $limit."
128+
while ($changelog.Length -gt $limit) {
129+
$lastNewlineIndex = $changelog.LastIndexOf("`n")
130+
if ($lastNewlineIndex -eq -1) {
131+
# No newlines found, just truncate to limit
132+
$changelog = $changelog.Substring(0, $limit)
81133
break
82134
}
135+
$changelog = $changelog.Substring(0, $lastNewlineIndex)
83136
}
84-
catch {}
137+
$changelog += "`n`n> :warning: **Changelog content truncated by $($oldLength - $changelog.Length) characters because it was over the limit ($limit) and wouldn't fit into PR description.**"
85138
}
139+
140+
Write-Host "Final changelog length: $($changelog.Length) characters"
141+
Write-Output $changelog
86142
}
87143
}
88-
catch {}
89-
}
90-
91-
# Slice changelog lines from startIndex to endIndex.
92-
if ($startIndex -ge 0)
93-
{
94-
$changelog = ($lines[$startIndex..$endIndex] -join "`n").Trim()
95-
}
96-
else
97-
{
98-
$changelog = ''
99-
}
100-
if ($changelog.Length -gt 1)
101-
{
102-
$changelog = "# Changelog`n$changelog"
103-
# Increase header level by one.
104-
$changelog = $changelog -replace '(^|\n)(#+) ', '$1$2# '
105-
# Remove at-mentions.
106-
$changelog = $changelog -replace '@', ''
107-
# Make PR/issue references into links to the original repository (unless they already are links).
108-
$changelog = $changelog -replace '(?<!\[)#([0-9]+)(?![\]0-9])', ('[#$1](' + $RepoUrl + '/issues/$1)')
109-
# Replace any links pointing to github.com so that the target PRs/Issues don't get na notification.
110-
$changelog = $changelog -replace ('\(' + $prefix), '(https://github-redirect.dependabot.com/'
111-
}
112144

113-
# Limit the changelog length to ~60k to allow for other text in the PR body (total PR limit is 65536 characters).
114-
$limit = 60000
115-
if ($changelog.Length -gt $limit)
116-
{
117-
$oldLength = $changelog.Length
118-
Write-Warning "Truncating changelog because it's $($changelog.Length - $limit) characters longer than the limit $limit."
119-
while ($changelog.Length -gt $limit)
120-
{
121-
$changelog = $changelog.Substring(0, $changelog.LastIndexOf("`n"))
145+
Write-Host "No changelog additions found between $OldTag and $NewTag"
146+
} catch {
147+
Write-Warning "Failed to get changelog: $($_.Exception.Message)"
148+
} finally {
149+
if (Test-Path $tmpDir) {
150+
Write-Host 'Cleaning up temporary files...'
151+
Remove-Item -Recurse -Force -ErrorAction Continue $tmpDir
152+
Write-Host 'Cleanup complete.'
122153
}
123-
$changelog += "`n`n> :warning: **Changelog content truncated by $($oldLength - $changelog.Length) characters because it was over the limit ($limit) and wouldn't fit into PR description.**"
124154
}
125155

126-
$changelog
156+
# This resets the $LASTEXITCODE set by git diff above.
157+
# Note that this only runs in the successful path.
158+
exit 0

0 commit comments

Comments
 (0)