Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -2,6 +2,10 @@

## Unreleased

### Features

- Updater now supports repositories without changelog files by falling back to git commit messages ([#116](https://github.com/getsentry/github-workflows/pull/116))

### Breaking Changes

Updater and Danger reusable workflows are now composite actions ([#114](https://github.com/getsentry/github-workflows/pull/114))
Expand Down
220 changes: 158 additions & 62 deletions updater/scripts/get-changelog.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,68 @@ function Get-ChangelogContent {
return $false
}

try {
Write-Host 'Fetching CHANGELOG files for comparison...'
# Function to generate changelog from git commits
function Get-ChangelogFromCommits {
param($repoUrl, $oldTag, $newTag, $tmpDir)

# Fetch old changelog
$oldChangelogPath = Join-Path $tmpDir 'old-changelog.md'
if (-not (Get-ChangelogContent $OldTag $oldChangelogPath)) {
Write-Warning "Could not find changelog at $OldTag"
return
}
# Clone the repository
$repoDir = Join-Path $tmpDir 'repo'
Write-Host "Cloning repository to generate changelog from commits..."

# Fetch new changelog
$newChangelogPath = Join-Path $tmpDir 'new-changelog.md'
if (-not (Get-ChangelogContent $NewTag $newChangelogPath)) {
Write-Warning "Could not find changelog at $NewTag"
return
# Clone with limited depth for performance, but ensure we have both tags
git clone --depth=200 --no-single-branch --quiet $repoUrl $repoDir 2>&1 | Out-Null
Comment thread
vaind marked this conversation as resolved.
Outdated

Comment thread
vaind marked this conversation as resolved.
Outdated
Push-Location $repoDir
try {
# Ensure we have both tags
git fetch --tags --quiet 2>&1 | Out-Null

# Get commit messages between tags
Write-Host "Getting commits between $oldTag and $newTag..."
$commitMessages = git log "$oldTag..$newTag" --pretty=format:'%s' 2>&1

if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not get commits between $oldTag and $newTag"
return $null
}

if ([string]::IsNullOrEmpty($commitMessages)) {
Comment thread
vaind marked this conversation as resolved.
Outdated
Write-Host "No commits found between $oldTag and $newTag"
return $null
Comment thread
vaind marked this conversation as resolved.
Outdated
}

# Filter out version tag commits and format as list
$commits = $commitMessages -split "`n" |
Where-Object {
$_ -and
$_ -notmatch '^\s*v?\d+\.\d+\.\d+' -and # Skip version commits
$_.Trim().Length -gt 0
} |
ForEach-Object { "- $_" }

if ($commits.Count -eq 0) {
Write-Host "No meaningful commits found between $oldTag and $newTag"
return $null
}

# Create changelog from commits
$changelog = "## Changelog`n`n"
$changelog += "### Commits between $oldTag and $newTag`n`n"
$changelog += $commits -join "`n"

Write-Host "Generated changelog from $($commits.Count) commits"
return $changelog
}
finally {
Pop-Location
}
Comment thread
vaind marked this conversation as resolved.
}

# Function to generate changelog from diff between changelog files
function Get-ChangelogFromDiff {
param($oldChangelogPath, $newChangelogPath, $oldTag, $newTag)

Write-Host "Generating changelog diff between $OldTag and $NewTag..."
Write-Host "Generating changelog diff between $oldTag and $newTag..."

# Generate diff using git diff --no-index
# git diff returns exit code 1 when differences are found, which is expected behavior
Expand All @@ -80,69 +124,121 @@ try {
# The first lines are diff metadata, skip them
$fullDiff = $fullDiff -split "`n" | Select-Object -Skip 4
if ([string]::IsNullOrEmpty("$fullDiff")) {
Write-Host "No differences found between $OldTag and $NewTag"
return
Write-Host "No differences found between $oldTag and $newTag"
return $null
} else {
Write-Host "Successfully created a changelog diff - $($fullDiff.Count) lines"
}

# Extract only the added lines (lines starting with + but not ++)
$addedLines = $fullDiff | Where-Object { $_ -match '^[+][^+]*' } | ForEach-Object { $_.Substring(1) }

if ($addedLines.Count -gt 0) {
# Create clean changelog from added lines
$changelog = ($addedLines -join "`n").Trim()
if ($addedLines.Count -eq 0) {
Write-Host "No changelog additions found between $oldTag and $newTag"
return $null
}

# Apply formatting to clean changelog
if ($changelog.Length -gt 0) {
# Add header
if (-not ($changelog -match '^(##|#) Changelog')) {
$changelog = "## Changelog`n`n$changelog"
}
# Create clean changelog from added lines
$changelog = ($addedLines -join "`n").Trim()

# Increase header level by one for content (not the main header)
$changelog = $changelog -replace '(^|\n)(#+) ', '$1$2# ' -replace '^### Changelog', '## Changelog'
if ($changelog.Length -eq 0) {
return $null
}

# Only add details section if there are deletions or modifications (not just additions)
$hasModifications = $fullDiff | Where-Object { $_ -match '^[-]' -and $_ -notmatch '^[-]{3}' }
if ($hasModifications) {
$changelog += "`n`n<details>`n<summary>Full CHANGELOG.md diff</summary>`n`n"
$changelog += '```diff' + "`n"
$changelog += $fullDiff -join "`n"
$changelog += "`n" + '```' + "`n`n</details>"
}
# Add header if needed
if (-not ($changelog -match '^(##|#) Changelog')) {
$changelog = "## Changelog`n`n$changelog"
}

# Apply standard formatting
# Remove at-mentions.
$changelog = $changelog -replace '@', ''
# Make PR/issue references into links to the original repository (unless they already are links).
$changelog = $changelog -replace '(?<!\[)#([0-9]+)(?![\]0-9])', ('[#$1](' + $RepoUrl + '/issues/$1)')
# Replace any links pointing to github.com so that the target PRs/Issues don't get na notification.
$changelog = $changelog -replace ('\(' + $prefix), '(https://github-redirect.dependabot.com/'
Comment thread
vaind marked this conversation as resolved.

# Limit the changelog length to ~60k to allow for other text in the PR body (total PR limit is 65536 characters).
$limit = 60000
if ($changelog.Length -gt $limit) {
$oldLength = $changelog.Length
Write-Warning "Truncating changelog because it's $($changelog.Length - $limit) characters longer than the limit $limit."
while ($changelog.Length -gt $limit) {
$lastNewlineIndex = $changelog.LastIndexOf("`n")
if ($lastNewlineIndex -eq -1) {
# No newlines found, just truncate to limit
$changelog = $changelog.Substring(0, $limit)
break
}
$changelog = $changelog.Substring(0, $lastNewlineIndex)
}
$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.**"
}
# Increase header level by one for content (not the main header)
$changelog = $changelog -replace '(^|\n)(#+) ', '$1$2# ' -replace '^### Changelog', '## Changelog'

Write-Host "Final changelog length: $($changelog.Length) characters"
Write-Output $changelog
# Only add details section if there are deletions or modifications (not just additions)
$hasModifications = $fullDiff | Where-Object { $_ -match '^[-]' -and $_ -notmatch '^[-]{3}' }
if ($hasModifications) {
$changelog += "`n`n<details>`n<summary>Full CHANGELOG.md diff</summary>`n`n"
$changelog += '```diff' + "`n"
$changelog += $fullDiff -join "`n"
$changelog += "`n" + '```' + "`n`n</details>"
}

return $changelog
}

# Function to sanitize and format changelog content
function Format-ChangelogContent {
param($changelog, $repoUrl)

if ([string]::IsNullOrEmpty($changelog)) {
return $null
}

# Apply standard formatting
# Remove at-mentions
$changelog = $changelog -replace '@', ''

# Make PR/issue references into links to the original repository (unless they already are links)
$changelog = $changelog -replace '(?<!\[)#([0-9]+)(?![\]0-9])', ('[#$1](' + $repoUrl + '/issues/$1)')

# Replace any links pointing to github.com so that the target PRs/Issues don't get notification
$changelog = $changelog -replace ('\(' + $prefix), '(https://github-redirect.dependabot.com/'

# Limit the changelog length to ~60k to allow for other text in the PR body (total PR limit is 65536 characters)
$limit = 60000
if ($changelog.Length -gt $limit) {
$oldLength = $changelog.Length
Write-Warning "Truncating changelog because it's $($changelog.Length - $limit) characters longer than the limit $limit."
while ($changelog.Length -gt $limit) {
$lastNewlineIndex = $changelog.LastIndexOf("`n")
if ($lastNewlineIndex -eq -1) {
# No newlines found, just truncate to limit
$changelog = $changelog.Substring(0, $limit)
break
}
$changelog = $changelog.Substring(0, $lastNewlineIndex)
}
$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.**"
}

Write-Host "Final changelog length: $($changelog.Length) characters"
return $changelog
}

try {
Write-Host 'Fetching CHANGELOG files for comparison...'

# Fetch old changelog
$oldChangelogPath = Join-Path $tmpDir 'old-changelog.md'
$hasOldChangelog = Get-ChangelogContent $OldTag $oldChangelogPath

# Fetch new changelog
$newChangelogPath = Join-Path $tmpDir 'new-changelog.md'
$hasNewChangelog = Get-ChangelogContent $NewTag $newChangelogPath

$changelog = $null

# Try changelog file diff first, fall back to git commits if not available
if ($hasOldChangelog -and $hasNewChangelog) {
$changelog = Get-ChangelogFromDiff $oldChangelogPath $newChangelogPath $OldTag $NewTag
}

# Fall back to git commits if no changelog files or no diff found
if (-not $changelog) {
Write-Host "No changelog files found or no changes detected, falling back to git commits..."
$changelog = Get-ChangelogFromCommits $RepoUrl $OldTag $NewTag $tmpDir
}

Write-Host "No changelog additions found between $OldTag and $NewTag"
# Apply formatting and output result
if ($changelog) {
$formattedChangelog = Format-ChangelogContent $changelog $RepoUrl
if ($formattedChangelog) {
Write-Output $formattedChangelog
} else {
Write-Host "No changelog content to display after formatting"
}
} else {
Write-Host "No changelog found between $OldTag and $NewTag"
}
} catch {
Write-Warning "Failed to get changelog: $($_.Exception.Message)"
} finally {
Expand Down
55 changes: 55 additions & 0 deletions updater/tests/get-changelog.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,59 @@ Features, fixes and improvements in this release have been contributed by:
$actualLines[$i].Trim() | Should -Be $expectedLines[$i].Trim()
}
}

It 'falls back to git commits when no changelog files exist' {
# Test with a repository that doesn't have changelog files
$actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" `
-RepoUrl 'https://github.com/catchorg/Catch2' -OldTag 'v3.9.1' -NewTag 'v3.10.0'

$expected = @'
## Changelog

### Commits between v3.9.1 and v3.10.0

- Forbid deducing reference types for m_predicate in FilterGenerator ([#3005](https://github-redirect.dependabot.com/catchorg/Catch2/issues/3005))
- Make message macros (FAIL, WARN, INFO, etc) thread safe
- Improve performance of writing XML
- Improve performance of writing JSON values
- Don't add / to start of pkg-config file path when DESTDIR is unset
- Fix color mode detection on FreeBSD by adding platform macro
- Handle DESTDIR env var when generating pkgconfig files
'@

$actual | Should -Be $expected
}

It 'git commit fallback handles PR references correctly' {
# Test with a known repository and tags that contain PR references
$actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" `
-RepoUrl 'https://github.com/catchorg/Catch2' -OldTag 'v3.9.1' -NewTag 'v3.10.0'

# Check that PR references are converted to links with github-redirect
$actual | Should -Match '\[#3005\]\(https://github-redirect\.dependabot\.com/catchorg/Catch2/issues/3005\)'
# Should not contain raw @mentions
$actual | Should -Not -Match "@\w+"
}

It 'git commit fallback returns empty when no commits found' {
# Test with same tags (no commits between them)
$actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" `
-RepoUrl 'https://github.com/catchorg/Catch2' -OldTag 'v3.10.0' -NewTag 'v3.10.0'

$actual | Should -BeNullOrEmpty
}

It 'git commit fallback filters out version tag commits' {
# Test that version commits like "v3.10.0" are filtered out
$actual = & "$PSScriptRoot/../scripts/get-changelog.ps1" `
-RepoUrl 'https://github.com/catchorg/Catch2' -OldTag 'v3.9.0' -NewTag 'v3.10.0'

# Should not contain version tag lines (v3.9.1 and v3.10.0 are version tags in this range)
$actual | Should -Not -Match "- v3\.9\.1"
$actual | Should -Not -Match "- v3\.10\.0"
$actual | Should -Not -Match "- 3\.9\.1"
$actual | Should -Not -Match "- 3\.10\.0"
# But should contain meaningful commits
$actual | Should -Match "- Forbid deducing reference types"
}
}
Comment thread
vaind marked this conversation as resolved.
Loading