public/Update-Changelog.ps1
function Update-Changelog { <# .SYNOPSIS Takes all unreleased changes listed in changelog, adds them to a new version, and makes a new, blank Unreleased section. .DESCRIPTION This cmdlet automates the updating of changelogs in Keep a Changelog 1.0.0 format at release time. It takes all changes in the Unreleased section, adds them to a new section with a version number you specify, then makes a new, blank Unreleased section. .INPUTS This cmdlet does not accept pipeline input. .OUTPUTS This cmdlet does not generate output except in the event of an error or notice. .EXAMPLE Update-Changelog -ReleaseVersion 1.1.1 -LinkMode Automatic -LinkPattern @{FirstRelease="https://github.com/testuser/testrepo/tree/v{CUR}";NormalRelease="https://github.com/testuser/testrepo/compare/v{PREV}..v{CUR}";Unreleased="https://github.com/testuser/testrepo/compare/v{CUR}..HEAD"} Does not generate output, but: 1. Takes all Unreleased changes in .\CHANGELOG.md and adds them to a new release tagged with ReleaseVersion and today's date. 2. Updates links according to LinkPattern. 3. Creates a new, blank Unreleased section .LINK https://github.com/natescherer/ChangelogManagement #> [CmdletBinding()] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] # Version number for the new release [string]$ReleaseVersion, [parameter(Mandatory = $false)] [ValidateScript( { Test-Path -Path $_ })] # The path to the source changelog file; defaults to .\CHANGELOG.md [string]$Path = "CHANGELOG.md", [parameter(Mandatory = $false)] [ValidatePattern(".*\.md")] # The path to the output changelog file; defaults to the source file [string]$OutputPath = $Path, [parameter(Mandatory = $true)] # Mode used for adding links at the bottom of the Changelog for new versions. Can either be Automatic # (adding based on pattern provided via -LinkPattern), Manual (adding placeholders which # will need manually updated), None (not adding links), GitHub (adding based on GitHub Actions context), # or AzureDevOps (adding based on Azure Pipelines environment variables). # # GITHUB ACTIONS NOTE: You must be running in a Github Actions workflow to use GitHub option. # # AZURE DEVOPS NOTE: You must be running in an Azure Pipelines workflow to use AzureDevOps option. # Additionally, your default branch must be 'main', if it is not, you should use the Automatic option with # a custom pattern for your default branch. [ValidateSet("Automatic", "Manual", "None", "GitHub", "AzureDevOps")] [string]$LinkMode, [parameter(Mandatory = $false)] # Pattern used for adding links at the bottom of the Changelog when -LinkMode is set to Automatic. This # is a hashtable that defines the format for the three possible types of links needed: FirstRelease, NormalRelease, # and Unreleased. The current version in the patterns should be replaced with {CUR} and the previous # version with {PREV}. See examples for details on format of hashtable. [ValidateNotNullOrEmpty()] [hashtable]$LinkPattern ) $NL = [System.Environment]::NewLine if ((Get-Content -Path $Path -Raw) -like "*`r`n*") { $FileNewline = "`r`n" } else { $FileNewline = "`n" } if (($LinkMode -eq "Automatic") -and !($LinkPattern)) { throw "-LinkPattern must be used when -LinkMode is set to Automatic" } if ($LinkMode -eq "GitHub") { if (!$env:GITHUB_REPOSITORY) { throw "You must be running in GitHub Actions to use GitHub LinkMode" } $LinkPattern = @{ FirstRelease = "https://github.com/$env:GITHUB_REPOSITORY/tree/v{CUR}" NormalRelease = "https://github.com/$env:GITHUB_REPOSITORY/compare/v{PREV}..v{CUR}" Unreleased = "https://github.com/$env:GITHUB_REPOSITORY/compare/v{CUR}..HEAD" } } if ($LinkMode -eq "AzureDevOps") { if (!$env:SYSTEM_TASKDEFINITIONSURI) { throw "You must be running in Azure Pipelines to use AzureDevOps LinkMode" } $BaseUri = $env:SYSTEM_TASKDEFINITIONSURI + $env:SYSTEM_TEAMPROJECT + "/_git/" + $env:BUILD_REPOSITORY_NAME $LinkPattern = @{ FirstRelease = $BaseUri + "?version=GTv{CUR}" NormalRelease = $BaseUri + "/branchCompare?baseVersion=GTv{PREV}&targetVersion=GTv{CUR}&_a=commits" Unreleased = $BaseUri + "/branchCompare?baseVersion=GTv{CUR}&targetVersion=GBmain&_a=commits" } } $ChangelogData = Get-ChangelogData -Path $Path <# Create $NewRelease by removing header from old Unreleased section Using the regular expression '\r?\n' to look for either CRLF or just LF. This resolves issue #11. #> $NewRelease = $ChangelogData.Unreleased.RawData -replace "## \[Unreleased\]\r?\n", "" If ([string]::IsNullOrWhiteSpace($NewRelease)) { Throw "No changes detected in current release, exiting." } # Edit $NewRelease to add version number and today's date $Today = (Get-Date -Format 'o').Split('T')[0] $NewRelease = "## [$ReleaseVersion] - $Today$FileNewline" + $NewRelease # Inject links into footer if (($LinkMode -eq "Automatic") -or ($LinkMode -eq "GitHub") -or ($LinkMode -eq "AzureDevOps")) { if ($ChangelogData.Released -ne "") { $NewFooter = ("[Unreleased]: " + ($LinkPattern['Unreleased'] -replace "{CUR}", $ReleaseVersion) + "$FileNewline" + "[$ReleaseVersion]: " + (($LinkPattern['NormalRelease'] -replace "{CUR}", $ReleaseVersion) -replace "{PREV}", $ChangelogData.LastVersion) + "$FileNewline" + ($ChangelogData.Footer.Trim() -replace "\[Unreleased\].*", "").TrimStart($FileNewline)) } else { $NewFooter = ("[Unreleased]: " + ($LinkPattern['Unreleased'] -replace "{CUR}", $ReleaseVersion) + "$FileNewline" + "[$ReleaseVersion]: " + ($LinkPattern['FirstRelease'] -replace "{CUR}", $ReleaseVersion)) } } if ($LinkMode -eq "Manual") { if ($ChangelogData.Released -ne "") { $NewFooter = ("[Unreleased]: ENTER-URL-HERE$FileNewline" + "[$ReleaseVersion]: ENTER-URL-HERE$FileNewline" + ($ChangelogData.Footer.Trim() -replace "\[Unreleased\].*", "").TrimStart($FileNewline)) } else { $NewFooter = ("[Unreleased]: ENTER-URL-HERE$FileNewline" + "[$ReleaseVersion]: ENTER-URL-HERE") } Write-Output ("Because you selected LinkMode Manual, you will need to manually update the links at the " + "bottom of the output file.") } if ($LinkMode -eq "None") { $NewFooter = $ChangelogData.Footer.Trim() } # Build & write updated CHANGELOG.md $Output += $ChangelogData.Header $Output += "## [Unreleased]$FileNewline$FileNewline" $Output += $NewRelease if ($ChangelogData.Released) { foreach ($Release in $ChangelogData.Released) { $Output += $Release.RawData } } $Output += $NewFooter Set-Content -Value $Output -Path $OutputPath -NoNewline } |