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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ To update your existing Danger workflows:

### Features

- Updater now supports dependencies without changelog files by falling back to git commit messages ([#116](https://github.com/getsentry/github-workflows/pull/116))
- Danger - Improve conventional commit scope handling, and non-conventional PR title support ([#105](https://github.com/getsentry/github-workflows/pull/105))
- Add Proguard artifact endpoint for Android builds in sentry-server ([#100](https://github.com/getsentry/github-workflows/pull/100))
- Updater - Add CMake FetchContent support for automated dependency updates ([#104](https://github.com/getsentry/github-workflows/pull/104))
Expand Down
255 changes: 184 additions & 71 deletions updater/scripts/get-changelog.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ param(
)

Set-StrictMode -Version latest
$PSNativeCommandErrorActionPreference = $true
$PSNativeCommandErrorActionPreference = $false
$ErrorActionPreference = 'Stop'

$prefix = 'https?://(www\.)?github.com/'
Expand Down Expand Up @@ -45,104 +45,217 @@ 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..."
git clone --no-single-branch --quiet $repoUrl $repoDir
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not clone repository $repoUrl"
return $null
}

if (-not (Test-Path $repoDir)) {
Write-Warning "Repository directory was not created successfully"
return $null
}

Push-Location $repoDir
try {
# Ensure we have both tags
git fetch --tags --quiet
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not fetch tags from repository"
return $null
}

# Get commit messages between tags
Write-Host "Getting commits between $oldTag and $newTag..."
$commitMessages = git log "$oldTag..$newTag" --pretty=format:'%s'
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not get commits between $oldTag and $newTag (exit code: $LASTEXITCODE)"
return $null
}

if ([string]::IsNullOrEmpty($commitMessages)) {
Write-Host "No commits found between $oldTag and $newTag"
return $null
}

# 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
}
catch {
Write-Warning "Error generating changelog from commits: $($_.Exception.Message)"
return $null
}
finally {
Pop-Location
# Ensure repository directory is cleaned up
if (Test-Path $repoDir) {
try {
Remove-Item -Recurse -Force $repoDir -ErrorAction SilentlyContinue
Write-Host "Cleaned up temporary repository directory"
}
catch {
Write-Warning "Could not clean up temporary repository directory: $repoDir"
}
}
}
}

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

# Try to fetch changelog files for both tags
$oldChangelogPath = Join-Path $tmpDir 'old-changelog.md'
$hasOldChangelog = Get-ChangelogContent $oldTag $oldChangelogPath

# 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
$hasNewChangelog = Get-ChangelogContent $newTag $newChangelogPath

# Return null if we don't have both changelog files
if (-not $hasOldChangelog -or -not $hasNewChangelog) {
return $null
}

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
# We need to handle this properly when PSNativeCommandErrorActionPreference is enabled
$fullDiff = & {
$oldErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
try {
git diff --no-index $oldChangelogPath $newChangelogPath
} finally {
$ErrorActionPreference = $oldErrorActionPreference
}
}
$fullDiff = git diff --no-index $oldChangelogPath $newChangelogPath

# 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/'

# 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'

# 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)')

Write-Host "Final changelog length: $($changelog.Length) characters"
Write-Output $changelog
# 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...'

$changelog = $null

# Try changelog file diff first, fall back to git commits if not available
$changelog = Get-ChangelogFromDiff $OldTag $NewTag $tmpDir

# 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
Loading
Loading