@@ -45,24 +45,68 @@ function Get-ChangelogContent {
4545 return $false
4646}
4747
48- try {
49- Write-Host ' Fetching CHANGELOG files for comparison...'
48+ # Function to generate changelog from git commits
49+ function Get-ChangelogFromCommits {
50+ param ($repoUrl , $oldTag , $newTag , $tmpDir )
5051
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 "
55- return
56- }
52+ # Clone the repository
53+ $repoDir = Join-Path $tmpDir ' repo'
54+ Write-Host " Cloning repository to generate changelog from commits..."
5755
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 "
62- return
56+ # Clone with limited depth for performance, but ensure we have both tags
57+ git clone -- depth= 200 -- no- single- branch -- quiet $repoUrl $repoDir 2>&1 | Out-Null
58+
59+ Push-Location $repoDir
60+ try {
61+ # Ensure we have both tags
62+ git fetch -- tags -- quiet 2>&1 | Out-Null
63+
64+ # Get commit messages between tags
65+ Write-Host " Getting commits between $oldTag and $newTag ..."
66+ $commitMessages = git log " $oldTag ..$newTag " -- pretty= format:' %s' 2>&1
67+
68+ if ($LASTEXITCODE -ne 0 ) {
69+ Write-Warning " Could not get commits between $oldTag and $newTag "
70+ return $null
71+ }
72+
73+ if ([string ]::IsNullOrEmpty($commitMessages )) {
74+ Write-Host " No commits found between $oldTag and $newTag "
75+ return $null
76+ }
77+
78+ # Filter out version tag commits and format as list
79+ $commits = $commitMessages -split " `n " |
80+ Where-Object {
81+ $_ -and
82+ $_ -notmatch ' ^\s*v?\d+\.\d+\.\d+' -and # Skip version commits
83+ $_.Trim ().Length -gt 0
84+ } |
85+ ForEach-Object { " - $_ " }
86+
87+ if ($commits.Count -eq 0 ) {
88+ Write-Host " No meaningful commits found between $oldTag and $newTag "
89+ return $null
90+ }
91+
92+ # Create changelog from commits
93+ $changelog = " ## Changelog`n`n "
94+ $changelog += " ### Commits between $oldTag and $newTag `n`n "
95+ $changelog += $commits -join " `n "
96+
97+ Write-Host " Generated changelog from $ ( $commits.Count ) commits"
98+ return $changelog
99+ }
100+ finally {
101+ Pop-Location
63102 }
103+ }
104+
105+ # Function to generate changelog from diff between changelog files
106+ function Get-ChangelogFromDiff {
107+ param ($oldChangelogPath , $newChangelogPath , $oldTag , $newTag )
64108
65- Write-Host " Generating changelog diff between $OldTag and $NewTag ..."
109+ Write-Host " Generating changelog diff between $oldTag and $newTag ..."
66110
67111 # Generate diff using git diff --no-index
68112 # git diff returns exit code 1 when differences are found, which is expected behavior
@@ -80,69 +124,122 @@ try {
80124 # The first lines are diff metadata, skip them
81125 $fullDiff = $fullDiff -split " `n " | Select-Object - Skip 4
82126 if ([string ]::IsNullOrEmpty(" $fullDiff " )) {
83- Write-Host " No differences found between $OldTag and $NewTag "
84- return
127+ Write-Host " No differences found between $oldTag and $newTag "
128+ return $null
85129 } else {
86130 Write-Host " Successfully created a changelog diff - $ ( $fullDiff.Count ) lines"
87131 }
88132
89133 # Extract only the added lines (lines starting with + but not ++)
90134 $addedLines = $fullDiff | Where-Object { $_ -match ' ^[+][^+]*' } | ForEach-Object { $_.Substring (1 ) }
91135
92- if ($addedLines.Count -gt 0 ) {
93- # Create clean changelog from added lines
94- $changelog = ($addedLines -join " `n " ).Trim()
136+ if ($addedLines.Count -eq 0 ) {
137+ Write-Host " No changelog additions found between $oldTag and $newTag "
138+ return $null
139+ }
95140
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- }
141+ # Create clean changelog from added lines
142+ $changelog = ($addedLines -join " `n " ).Trim()
102143
103- # Increase header level by one for content (not the main header)
104- $changelog = $changelog -replace ' (^|\n)(#+) ' , ' $1$2# ' -replace ' ^### Changelog' , ' ## Changelog'
144+ if ($changelog.Length -eq 0 ) {
145+ return $null
146+ }
105147
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- }
148+ # Add header if needed
149+ if (-not ($changelog -match ' ^(##|#) Changelog' )) {
150+ $changelog = " ## Changelog`n`n $changelog "
151+ }
114152
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 )
133- break
134- }
135- $changelog = $changelog.Substring (0 , $lastNewlineIndex )
136- }
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.**"
138- }
153+ # Increase header level by one for content (not the main header)
154+ $changelog = $changelog -replace ' (^|\n)(#+) ' , ' $1$2# ' -replace ' ^### Changelog' , ' ## Changelog'
139155
140- Write-Host " Final changelog length: $ ( $changelog.Length ) characters"
141- Write-Output $changelog
156+ # Only add details section if there are deletions or modifications (not just additions)
157+ $hasModifications = $fullDiff | Where-Object { $_ -match ' ^[-]' -and $_ -notmatch ' ^[-]{3}' }
158+ if ($hasModifications ) {
159+ $changelog += " `n`n <details>`n <summary>Full CHANGELOG.md diff</summary>`n`n "
160+ $changelog += ' ```diff' + " `n "
161+ $changelog += $fullDiff -join " `n "
162+ $changelog += " `n " + ' ```' + " `n`n </details>"
163+ }
164+
165+ return $changelog
166+ }
167+
168+ # Function to sanitize and format changelog content
169+ function Format-ChangelogContent {
170+ param ($changelog , $repoUrl )
171+
172+ if ([string ]::IsNullOrEmpty($changelog )) {
173+ return $null
174+ }
175+
176+ # Apply standard formatting
177+ # Remove at-mentions
178+ $changelog = $changelog -replace ' @' , ' '
179+
180+ # Make PR/issue references into links to the original repository (unless they already are links)
181+ $changelog = $changelog -replace ' (?<!\[)#([0-9]+)(?![\]0-9])' , (' [#$1](' + $repoUrl + ' /issues/$1)' )
182+
183+ # Replace any links pointing to github.com so that the target PRs/Issues don't get notification
184+ $prefix = ' https?://(www\.)?github.com/'
185+ $changelog = $changelog -replace (' \(' + $prefix ), ' (https://github-redirect.dependabot.com/'
186+
187+ # Limit the changelog length to ~60k to allow for other text in the PR body (total PR limit is 65536 characters)
188+ $limit = 60000
189+ if ($changelog.Length -gt $limit ) {
190+ $oldLength = $changelog.Length
191+ Write-Warning " Truncating changelog because it's $ ( $changelog.Length - $limit ) characters longer than the limit $limit ."
192+ while ($changelog.Length -gt $limit ) {
193+ $lastNewlineIndex = $changelog.LastIndexOf (" `n " )
194+ if ($lastNewlineIndex -eq -1 ) {
195+ # No newlines found, just truncate to limit
196+ $changelog = $changelog.Substring (0 , $limit )
197+ break
198+ }
199+ $changelog = $changelog.Substring (0 , $lastNewlineIndex )
142200 }
201+ $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.**"
202+ }
203+
204+ Write-Host " Final changelog length: $ ( $changelog.Length ) characters"
205+ return $changelog
206+ }
207+
208+ try {
209+ Write-Host ' Fetching CHANGELOG files for comparison...'
210+
211+ # Fetch old changelog
212+ $oldChangelogPath = Join-Path $tmpDir ' old-changelog.md'
213+ $hasOldChangelog = Get-ChangelogContent $OldTag $oldChangelogPath
214+
215+ # Fetch new changelog
216+ $newChangelogPath = Join-Path $tmpDir ' new-changelog.md'
217+ $hasNewChangelog = Get-ChangelogContent $NewTag $newChangelogPath
218+
219+ $changelog = $null
220+
221+ # Try changelog file diff first, fall back to git commits if not available
222+ if ($hasOldChangelog -and $hasNewChangelog ) {
223+ $changelog = Get-ChangelogFromDiff $oldChangelogPath $newChangelogPath $OldTag $NewTag
224+ }
225+
226+ # Fall back to git commits if no changelog files or no diff found
227+ if (-not $changelog ) {
228+ Write-Host " No changelog files found or no changes detected, falling back to git commits..."
229+ $changelog = Get-ChangelogFromCommits $RepoUrl $OldTag $NewTag $tmpDir
143230 }
144231
145- Write-Host " No changelog additions found between $OldTag and $NewTag "
232+ # Apply formatting and output result
233+ if ($changelog ) {
234+ $formattedChangelog = Format-ChangelogContent $changelog $RepoUrl
235+ if ($formattedChangelog ) {
236+ Write-Output $formattedChangelog
237+ } else {
238+ Write-Host " No changelog content to display after formatting"
239+ }
240+ } else {
241+ Write-Host " No changelog found between $OldTag and $NewTag "
242+ }
146243} catch {
147244 Write-Warning " Failed to get changelog: $ ( $_.Exception.Message ) "
148245} finally {
0 commit comments