From bbebb4f68246bc807040100de60c99f3c35530d1 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Wed, 23 Dec 2020 09:05:51 -0800 Subject: [PATCH 01/18] Add changelog generator --- scripts/Get-Changelog.ps1 | 390 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 scripts/Get-Changelog.ps1 diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 new file mode 100644 index 00000000000000..4609296072ffe5 --- /dev/null +++ b/scripts/Get-Changelog.ps1 @@ -0,0 +1,390 @@ +#Requires -Version 5.0 +# We are not using Powershell >= 6.0, as the only supported debugger (vscode powershell extension) breaks on complex code. See: https://github.com/PowerShell/PowerShellEditorServices/issues/1295 +# This code can be run on PowerShell Core on any platform, but it is recommend to debug this code in Windows PowerShell ISE unless debugging happens to "just work" on your machine. +# Expect the fix to be out at around the end of 2020/beginning of 2021, at which point consider upgrading this script to PowerShell 7 the next time maintenance is necessary. +# -- Griffin Downs Dec 15, 2020 (@grdowns) + +using namespace System.Management.Automation +using namespace System.Collections.Generic + +<# +.Synopsis + Changelog generator for vcpkg. +.DESCRIPTION + The changelog generator uses the GitHub Pull Request and Files API's to get + pull requests and their associated file changes over the provided date range. + Then, the data is processed into buckets which are then presented to the user + in a markdown file. +.EXAMPLE + Get-Changelog +.EXAMPLE + Get-Changelog -StartDate 11/1/20 -EndDate 12/1/20 +.INPUTS + The Credentials object. +.OUTPUTS + A "CHANGELOG.md" file in the working directory. +#> +Param ( + # The begin date range (inclusive) + [Parameter(Mandatory=$true)] + [ValidateScript({$_ -le (Get-Date)})] + [DateTime]$StartDate, + + # The end date range (exclusive) + [Parameter(Mandatory=$true)] + [ValidateScript({$_ -le (Get-Date)})] + [DateTime]$EndDate, + + # GitHub credentials (username and PAT) + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Credential()] + [PSCredential]$Credentials +) + + +Set-StrictMode -Version 2 + + +function Get-AuthHeader { + @{ Authorization = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( + '{0}:{1}' -f ($Credentials.UserName, $Credentials.GetNetworkCredential().Password))) } +} + + +function Get-MergedPullRequests { + [CmdletBinding()] + [OutputType([Object[]])] + Param () + Begin { + $PullsUrl = 'https://api.github.com/repos/Microsoft/vcpkg/pulls' + $Body = @{ + state = 'closed' + sort = 'updated' + base = 'master' + per_page = 100 + direction = 'desc' + # In PowerShell 7 this can be used to increment the page instead of url hacking + #page = 1 + } + } + Process { + $page = 1 + while ($true) { + $splat = @{ + Uri = $PullsUrl + "?page=$page" + Body = $Body + ContentType = 'application/json' + } + $response = Invoke-RestMethod -Headers (Get-AuthHeader) @splat + + foreach ($_ in $response) { + # In PowerShell 7 this automatically happens + foreach ($x in 'created_at', 'merged_at', 'updated_at', 'closed_at') { + if ($_.$x) { $_.$x = [DateTime]::Parse($_.$x) } + } + + if (-not $_.merged_at) { continue } + if ($_.updated_at -lt $StartDate) { return } + if ($_.merged_at -ge $EndDate -or $_.merged_at -lt $StartDate) { continue } + + $_ + } + + #$Body.page++ + $page++ + } + } +} + + +class PRFileMap { + [PSCustomObject]$Pull + [PSCustomObject[]]$Files +} + + +function Get-PullRequestFileMap { + [CmdletBinding()] + [OutputType([PRFileMap])] + Param ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Object]$Pull + ) + Process { + [PRFileMap]@{ + Pull = $Pull + Files = & { + # The -FollowRelLink option in PowerShell 6 will automatically get all pages + $page = 1 + $pageLength = 100 + $mergeUrl = "https://api.github.com/repos/Microsoft/vcpkg/pulls/{0}/files" -f $Pull.number + do { + $splat = @{ + Uri = $mergeUrl + "?page=$page" + Body = @{ per_page = $pageLength } + ContentType = 'application/json' + } + $response = Invoke-RestMethod -Headers (Get-AuthHeader) @splat + + $page++ + $response + } until ($response.Length -lt $pageLength) + } + } + } +} + + +class DocumentationUpdate { + [String]$Path + [Boolean]$New + [List[Object]]$Pulls +} + + +function Select-Documentation { + [CmdletBinding()] + [OutputType([DocumentationUpdate])] + Param ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [PRFileMap]$PRFileMap + ) + Begin { + $UpdatedDocumentation = @{} + } + Process { + $PRFileMap.Files | ForEach-Object { + if ($_.filename -notlike 'docs/*') { return } + + $new = $_.status -eq 'added' + if ($entry = $UpdatedDocumentation[$_.filename]) { + $entry.Pulls += $PRFileMap.Pull + $entry.New = $entry.New -or $new + } else { + $UpdatedDocumentation[$_.filename] = @{ + Pulls = [List[Object]]::new(@($PRFileMap.Pull)) + New = $new + } + } + } + } + End { + $UpdatedDocumentation.GetEnumerator() | ForEach-Object { + [DocumentationUpdate]@{ + Path = $_.Key + Pulls = $_.Value.Pulls + New = $_.Value.New + } + } + } +} + + +function Select-InfrastructurePullRequests { + [CmdletBinding()] + [OutputType([Object])] + Param ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [PRFileMap]$PRFileMap + ) + Process { + switch -Wildcard ($PRFileMap.Files | Get-Member filename) { + "docs/*" { continue } + "ports/*" { continue } + Default { return $PRFileMap.Pull } + } + } +} + + +class Version { + [String]$Begin + [String]$End + [String]$BeginPort + [String]$EndPort +} + + +function Select-Version { + [CmdletBinding()] + [OutputType([Version])] + Param ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Object]$VersionFile + ) + Begin { + $V = [Version]@{} + } + Process { + $regex = switch ($VersionFile.filename | Split-Path -Leaf) { + 'CONTROL' { + '(?^[\+|\-]|)(?Version|[\+|\-]Port-Version):\s(?\S+)' + } + 'vcpkg.json' { + '(?^[\+|\-]|)\s*\"(?version-string|port-version)\":\s\"(?.+)\"' + } + Default { return } + } + + $VersionFile.Patch -split '\n' | ForEach-Object { + if ($_ -notmatch $regex) { return } + + $m = $Matches + switch -Wildcard ($m.operation + $m.field) { + 'Version*' { $V.Begin = $V.End = $m.version } + '-Version*' { $V.Begin = ($V.Begin, $m.version | Measure-Object -Minimum).Minimum } + '+Version*' { $V.End = ($V.End, $m.version | Measure-Object -Minimum).Minimum } + 'Port-Version' { $V.BeginPort = $V.EndPort = $m.version } + '-Port-Version' { $V.BeginPort = ($V.BeginPort, $m.version | Measure-Object -Minimum).Minimum } + '+Port-Version' { $V.EndPort = ($V.EndPort, $m.version | Measure-Object -Maximum).Maximum } + } + } + } + End { + if (-not $V.Begin) { $V.Begin = $V.End } + elseif (-not $V.End) { $V.End = $V.Begin } + + if (-not $V.BeginPort) { $V.BeginPort = '0' } + if (-not $V.EndPort) { $V.EndPort = '0' } + + $V + } +} + + +class PortUpdate { + [String]$Port + [Object[]]$Pulls + [Version]$Version + [Boolean]$New + [String[]]$Authors +} + + +function Select-UpdatedPorts { + [CmdletBinding()] + [OutputType([PortUpdate])] + Param ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [PRFileMap]$PRFileMap + ) + Begin { + $ModifiedPorts = @{} + } Process { + $PRFileMap.Files | Where-Object { + $_.filename -like 'ports/*/CONTROL' -or + $_.filename -like 'ports/*/vcpkg.json' + } | ForEach-Object { + $port = $_.filename.split('/')[1] + if ($entry = $ModifiedPorts[$port]) { + $entry.VersionFiles += $_ + if (-not $entry.Pulls.Contains($PRFileMap.Pull)) { $entry.Pulls += $PRFileMap.Pull } + } else { + $ModifiedPorts[$port] = @{ + VersionFiles = [List[Object]]::new(@($_)) + Pulls = [List[Object]]::new(@($PRFileMap.Pull)) + } + } + } + } + End { + $ModifiedPorts.GetEnumerator() | ForEach-Object { + $versionFiles = $_.Value.VersionFiles + if (-not ($versionChange = $versionFiles | Select-Version)) { return } + + function Find-File($x) { $versionFiles | Where-Object { $_.filename -like "*$x" } } + function Find-NewFile($x) + { $versionFiles | Where-Object { $_.filename -like "*$x" -and $_.status -eq 'added' } } + + [PortUpdate]@{ + Port = $_.Key + Pulls = $_.Value.Pulls + Version = $versionChange + New = Find-NewFile 'CONTROL' -or (-not (Find-File 'CONTROL') -and (Find-NewFile 'vcpkg.json')) + Authors = $_.Value.Pulls | ForEach-Object { $_.user.login } | Get-Unique + } + } + } +} + +$PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap +$UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object -Property 'New' -Descending +$UpdatedInfrastructure = $PRFileMaps | Select-InfrastructurePullRequests +$UpdatedPorts = $PRFileMaps | Select-UpdatedPorts +$NewPorts = $UpdatedPorts | Where-Object { $_.New } +$ChangedPorts = $UpdatedPorts | Where-Object { -not $_.New } + +@" +vcpkg ($($StartDate.ToString('yyyy.MM.dd')) - $((($EndDate).AddSeconds(-1)).ToString('yyyy.MM.dd'))) +--- +#### Total port count: +#### Total port count per triplet (tested): +|triplet|ports available| +|---|---| +|**x64-windows**|NUM| +|x86-windows|NUM| +|x64-windows-static|NUM| +|**x64-osx**|NUM| +|**x64-linux**|NUM| +|arm64-windows|NUM| +|x64-uwp|NUM| +|arm-uwp|NUM| + +#### The following commands and options have been updated: + +#### The following documentation has been updated: + +$(-join ($UpdatedDocumentation | ForEach-Object { + "- [TITLE]({0}){1}`n" -f $_.Path, (& { if ($_.New) { ' ***[NEW]***' } else { '' } }) + + $_.Pulls | ForEach-Object { + " - [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login + } +})) + +#### The following *remarkable* changes have been made to vcpkg's infrastructure: + +
+The following additional changes have been made to vcpkg's infrastructure: + +$(-join ($UpdatedInfrastructure | ForEach-Object { + "- [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login +})) +
+ +
+The following $($NewPorts.Length) ports have been added: + +|port|version| +|---|---| +$(-join ($NewPorts | ForEach-Object { + "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url + + if ($_.Pulls.Length -gt 1 ) { + '' + $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { + "[#{0}]({1})" -f $_.number, $_.html_url + } + '' + } + + "|{0}`n" -f $_.Version.End +})) +
+ +
+The following $($ChangedPorts.Length) ports have been updated: + +$(-join ($ChangedPorts | ForEach-Object { + "- {0} ``{1}#{2}``" -f $_.Port, $_.Version.Begin, $_.Version.BeginPort + ' -> ' + "``{0}#{1}```n" -f $_.Version.End, $_.Version.EndPort + + $_.Pulls | ForEach-Object { + " - [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login + } +})) +
+ +-- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") +"@ | Out-File 'CHANGELOG.md' \ No newline at end of file From b7df3fed4a9db705ec9ed98226b7093f47b421cc Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Wed, 23 Dec 2020 09:19:10 -0800 Subject: [PATCH 02/18] Add newline --- scripts/Get-Changelog.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 4609296072ffe5..2d927c4f4e4b31 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -387,4 +387,4 @@ $(-join ($ChangedPorts | ForEach-Object { -- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") -"@ | Out-File 'CHANGELOG.md' \ No newline at end of file +"@ | Out-File 'CHANGELOG.md' From ded07d10e5da57212a52a6f64be9d35ae624d8a1 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Wed, 23 Dec 2020 09:40:38 -0800 Subject: [PATCH 03/18] Remove unused var --- scripts/Get-Changelog.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 2d927c4f4e4b31..66aaa2b90d6733 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -257,7 +257,6 @@ class PortUpdate { [Object[]]$Pulls [Version]$Version [Boolean]$New - [String[]]$Authors } @@ -301,7 +300,6 @@ function Select-UpdatedPorts { Pulls = $_.Value.Pulls Version = $versionChange New = Find-NewFile 'CONTROL' -or (-not (Find-File 'CONTROL') -and (Find-NewFile 'vcpkg.json')) - Authors = $_.Value.Pulls | ForEach-Object { $_.user.login } | Get-Unique } } } From a2bcef2c0f854edac72c6ec73ea265bf27d711e6 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Wed, 23 Dec 2020 18:02:42 -0800 Subject: [PATCH 04/18] Fix version change end set to minimum; Formatting --- scripts/Get-Changelog.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 66aaa2b90d6733..fe12207f1c81d4 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -233,7 +233,7 @@ function Select-Version { switch -Wildcard ($m.operation + $m.field) { 'Version*' { $V.Begin = $V.End = $m.version } '-Version*' { $V.Begin = ($V.Begin, $m.version | Measure-Object -Minimum).Minimum } - '+Version*' { $V.End = ($V.End, $m.version | Measure-Object -Minimum).Minimum } + '+Version*' { $V.End = ($V.End, $m.version | Measure-Object -Maximum).Maximum } 'Port-Version' { $V.BeginPort = $V.EndPort = $m.version } '-Port-Version' { $V.BeginPort = ($V.BeginPort, $m.version | Measure-Object -Minimum).Minimum } '+Port-Version' { $V.EndPort = ($V.EndPort, $m.version | Measure-Object -Maximum).Maximum } @@ -358,7 +358,7 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - if ($_.Pulls.Length -gt 1 ) { + if ($_.Pulls.Length -gt 1) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { "[#{0}]({1})" -f $_.number, $_.html_url From 34b75e871a0be9487c1316e68051bca17bcbbb37 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Wed, 23 Dec 2020 18:04:44 -0800 Subject: [PATCH 05/18] Add cmdletbinding; Capitalize bool values; Strip whitespace --- scripts/Get-Changelog.ps1 | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index fe12207f1c81d4..15a4d0d082f18c 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -24,19 +24,20 @@ using namespace System.Collections.Generic .OUTPUTS A "CHANGELOG.md" file in the working directory. #> +[CmdletBinding(PositionalBinding=$False)] Param ( # The begin date range (inclusive) - [Parameter(Mandatory=$true)] + [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, - + # The end date range (exclusive) - [Parameter(Mandatory=$true)] + [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$EndDate, - + # GitHub credentials (username and PAT) - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [Credential()] [PSCredential]$Credentials ) @@ -69,7 +70,7 @@ function Get-MergedPullRequests { } Process { $page = 1 - while ($true) { + while ($True) { $splat = @{ Uri = $PullsUrl + "?page=$page" Body = $Body @@ -98,8 +99,8 @@ function Get-MergedPullRequests { class PRFileMap { - [PSCustomObject]$Pull - [PSCustomObject[]]$Files + [Object]$Pull + [Object[]]$Files } @@ -107,7 +108,7 @@ function Get-PullRequestFileMap { [CmdletBinding()] [OutputType([PRFileMap])] Param ( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [Object]$Pull ) Process { @@ -146,7 +147,7 @@ function Select-Documentation { [CmdletBinding()] [OutputType([DocumentationUpdate])] Param ( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [PRFileMap]$PRFileMap ) Begin { @@ -184,7 +185,7 @@ function Select-InfrastructurePullRequests { [CmdletBinding()] [OutputType([Object])] Param ( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [PRFileMap]$PRFileMap ) Process { @@ -209,7 +210,7 @@ function Select-Version { [CmdletBinding()] [OutputType([Version])] Param ( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [Object]$VersionFile ) Begin { @@ -264,7 +265,7 @@ function Select-UpdatedPorts { [CmdletBinding()] [OutputType([PortUpdate])] Param ( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [PRFileMap]$PRFileMap ) Begin { @@ -357,7 +358,7 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { |---|---| $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - + if ($_.Pulls.Length -gt 1) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { From f4a8a189db2ff3e0ea6bf4ddbb26771d1360e0ee Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Thu, 31 Dec 2020 22:24:06 -0800 Subject: [PATCH 06/18] Add suffix to output file if name exists; Formatting; Examples --- scripts/Get-Changelog.ps1 | 45 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 15a4d0d082f18c..91ac5d0c8af119 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -9,22 +9,24 @@ using namespace System.Collections.Generic <# .Synopsis - Changelog generator for vcpkg. + Changelog generator for vcpkg. .DESCRIPTION - The changelog generator uses the GitHub Pull Request and Files API's to get - pull requests and their associated file changes over the provided date range. - Then, the data is processed into buckets which are then presented to the user - in a markdown file. + The changelog generator uses the GitHub Pull Request and Files API's to get + pull requests and their associated file changes over the provided date range. + Then, the data is processed into buckets which are then presented to the user + in a markdown file. .EXAMPLE - Get-Changelog + Get-Changelog .EXAMPLE - Get-Changelog -StartDate 11/1/20 -EndDate 12/1/20 -.INPUTS - The Credentials object. + Get-Changelog -StartDate 11/1/20 -EndDate 12/1/20 +.EXAMPLE + $cred = Get-Credential + Get-Changelog -Credentials $cred .OUTPUTS - A "CHANGELOG.md" file in the working directory. + A "CHANGELOG.md" file in the working directory. If the file already exists, + #> -[CmdletBinding(PositionalBinding=$False)] +[CmdletBinding(PositionalBinding=$True)] Param ( # The begin date range (inclusive) [Parameter(Mandatory=$True)] @@ -189,7 +191,7 @@ function Select-InfrastructurePullRequests { [PRFileMap]$PRFileMap ) Process { - switch -Wildcard ($PRFileMap.Files | Get-Member filename) { + switch -Wildcard ($PRFileMap.Files | Get-Member 'filename') { "docs/*" { continue } "ports/*" { continue } Default { return $PRFileMap.Pull } @@ -270,7 +272,8 @@ function Select-UpdatedPorts { ) Begin { $ModifiedPorts = @{} - } Process { + } + Process { $PRFileMap.Files | Where-Object { $_.filename -like 'ports/*/CONTROL' -or $_.filename -like 'ports/*/vcpkg.json' @@ -306,6 +309,20 @@ function Select-UpdatedPorts { } } +function Get-ChangelogFileName() { + $suffixes = Get-ChildItem -Path . | ForEach-Object { + if($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md') { + if ($Matches.number) { $Matches.number } else { '0' } + } + } | Sort-Object + + $count = 0 + while ([String]$count -in $suffixes) { $count++ } + + $suffix = if ($count) { "-$count" } else { '' } + "CHANGELOG$suffix.md" +} + $PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap $UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object -Property 'New' -Descending $UpdatedInfrastructure = $PRFileMaps | Select-InfrastructurePullRequests @@ -386,4 +403,4 @@ $(-join ($ChangedPorts | ForEach-Object { -- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") -"@ | Out-File 'CHANGELOG.md' +"@ | Out-File (Get-ChangelogFileName) From 88d8096ad3ced14d369d31140e59261b07480af6 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 00:34:49 -0800 Subject: [PATCH 07/18] Add credentials validation, progress bar; Fix file naming --- scripts/Get-Changelog.ps1 | 162 +++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 53 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 91ac5d0c8af119..ab053cbbe7b9ca 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -32,14 +32,14 @@ Param ( [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, - + # The end date range (exclusive) [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$EndDate, - + # GitHub credentials (username and PAT) - [Parameter(Mandatory=$True,ValueFromPipeline=$True)] + [Parameter(Mandatory=$False,ValueFromPipeline=$True)] [Credential()] [PSCredential]$Credentials ) @@ -47,10 +47,25 @@ Param ( Set-StrictMode -Version 2 +if (-not $Credentials) { + $Credentials = Get-Credential -Message 'Enter GitHub Credentials (username and PAT)' + if (-not $Credentials) { + throw [System.ArgumentException]::new( + 'Cannot process command because of the missing mandatory parameter: Credentials.' + ) + } +} + +function Get-AuthHeader() { + @{ Authorization = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( + ('{0}:{1}' -f $Credentials.UserName, $Credentials.GetNetworkCredential().Password))) } +} -function Get-AuthHeader { - @{ Authorization = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( - '{0}:{1}' -f ($Credentials.UserName, $Credentials.GetNetworkCredential().Password))) } +$response = Invoke-WebRequest -uri 'https://api.github.com' -Headers ($Credentials | Get-AuthHeader) +if ('X-OAuth-Scopes' -notin $response.Headers.Keys) { + throw [System.ArgumentException]::new( + "Cannot validate argument on parameter 'Credentials'. Incorrect GitHub credentials" + ) } @@ -59,42 +74,53 @@ function Get-MergedPullRequests { [OutputType([Object[]])] Param () Begin { - $PullsUrl = 'https://api.github.com/repos/Microsoft/vcpkg/pulls' - $Body = @{ - state = 'closed' - sort = 'updated' - base = 'master' - per_page = 100 - direction = 'desc' - # In PowerShell 7 this can be used to increment the page instead of url hacking - #page = 1 + $RequestSplat = @{ + Uri = 'https://api.github.com/repos/Microsoft/vcpkg/pulls' + Body = @{ + state = 'closed' + sort = 'updated' + base = 'master' + per_page = 100 + direction = 'desc' + page = 1 + } + } + $Epoch = Get-Date + $DeltaEpochStart = ($Epoch - $StartDate).Ticks + + $ProgressSplat = @{ + Activity = 'Searching for merged Pull Requests in date range: {0} - {1}' -f + $StartDate.ToString('yyyy.MM.dd'), $EndDate.ToString('yyyy.MM.dd') + PercentComplete = 0 + } + + Write-Progress @ProgressSplat + + $writeProgress = { + $ProgressSplat.PercentComplete = 100 * ($Epoch - $_.updated_at).Ticks / $DeltaEpochStart + Write-Progress @ProgressSplat -Status ('Current item date: {0}' -f $_.updated_at.ToString('yyyy.MM.dd')) } } Process { - $page = 1 while ($True) { - $splat = @{ - Uri = $PullsUrl + "?page=$page" - Body = $Body - ContentType = 'application/json' - } - $response = Invoke-RestMethod -Headers (Get-AuthHeader) @splat + $response = Invoke-WebRequest -Headers (Get-AuthHeader) @RequestSplat | ConvertFrom-Json foreach ($_ in $response) { - # In PowerShell 7 this automatically happens foreach ($x in 'created_at', 'merged_at', 'updated_at', 'closed_at') { if ($_.$x) { $_.$x = [DateTime]::Parse($_.$x) } } if (-not $_.merged_at) { continue } if ($_.updated_at -lt $StartDate) { return } + + &$WriteProgress + if ($_.merged_at -ge $EndDate -or $_.merged_at -lt $StartDate) { continue } $_ } - #$Body.page++ - $page++ + $RequestSplat.Body.page++ } } } @@ -108,31 +134,54 @@ class PRFileMap { function Get-PullRequestFileMap { [CmdletBinding()] - [OutputType([PRFileMap])] + [OutputType([PRFileMap[]])] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [Object]$Pull ) + Begin { + $Pulls = [List[Object]]::new() + + $ProgressSplat = @{ + Activity = 'Getting Pull Request files' + PercentComplete = 0 + } + + $Count = 0 + $WriteProgress = { + $ProgressSplat.Status = 'Getting files for: #{0} ({1}/{2})' -f $_.number, $Count, $Pulls.Length + $ProgressSplat.PercentComplete = 100 * $Count / $Pulls.Length + Write-Progress @ProgressSplat + } + } Process { - [PRFileMap]@{ - Pull = $Pull - Files = & { - # The -FollowRelLink option in PowerShell 6 will automatically get all pages - $page = 1 - $pageLength = 100 - $mergeUrl = "https://api.github.com/repos/Microsoft/vcpkg/pulls/{0}/files" -f $Pull.number - do { - $splat = @{ - Uri = $mergeUrl + "?page=$page" - Body = @{ per_page = $pageLength } - ContentType = 'application/json' + $Pulls += $Pull + } + End { + Write-Progress @ProgressSplat + $ProgressSplat += @{ Status = '' } + + $Pulls | ForEach-Object { + $Count++ + + [PRFileMap]@{ + Pull = $_ + Files = $( + $requestSplat = @{ + Uri = 'https://api.github.com/repos/Microsoft/vcpkg/pulls/{0}/files' -f $_.number + Body = @{ page = 0; per_page = 100 } } - $response = Invoke-RestMethod -Headers (Get-AuthHeader) @splat + do { + $requestSplat.Body.page++ - $page++ - $response - } until ($response.Length -lt $pageLength) + $response = Invoke-WebRequest -Headers (Get-AuthHeader) @requestSplat | ConvertFrom-Json + + $response + } until ($response.Length -lt $requestSplat.Body.per_page) + ) } + + &$WriteProgress } } } @@ -236,7 +285,7 @@ function Select-Version { switch -Wildcard ($m.operation + $m.field) { 'Version*' { $V.Begin = $V.End = $m.version } '-Version*' { $V.Begin = ($V.Begin, $m.version | Measure-Object -Minimum).Minimum } - '+Version*' { $V.End = ($V.End, $m.version | Measure-Object -Maximum).Maximum } + '+Version*' { $V.End = ($V.End, $m.version | Measure-Object -Minimum).Minimum } 'Port-Version' { $V.BeginPort = $V.EndPort = $m.version } '-Port-Version' { $V.BeginPort = ($V.BeginPort, $m.version | Measure-Object -Minimum).Minimum } '+Port-Version' { $V.EndPort = ($V.EndPort, $m.version | Measure-Object -Maximum).Maximum } @@ -311,25 +360,30 @@ function Select-UpdatedPorts { function Get-ChangelogFileName() { $suffixes = Get-ChildItem -Path . | ForEach-Object { - if($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md') { - if ($Matches.number) { $Matches.number } else { '0' } - } + if (-not($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md')) { return } + if ($Matches.PSObject.Properties.Name -contains 'number') { $Matches.number } else { '0' } } | Sort-Object - $count = 0 - while ([String]$count -in $suffixes) { $count++ } + $suffix = 0 + while ([String]$suffix -in $suffixes) { $suffix++ } - $suffix = if ($count) { "-$count" } else { '' } + $suffix = if ($suffix) { "-$suffix" } else { '' } "CHANGELOG$suffix.md" } -$PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap +$PRFileMaps = (Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap) + +Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 + $UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object -Property 'New' -Descending $UpdatedInfrastructure = $PRFileMaps | Select-InfrastructurePullRequests $UpdatedPorts = $PRFileMaps | Select-UpdatedPorts $NewPorts = $UpdatedPorts | Where-Object { $_.New } $ChangedPorts = $UpdatedPorts | Where-Object { -not $_.New } +Write-Progress -Activity 'Selecting updates from pull request files' -Completed + +Write-Progress -Activity 'Writing changelog file' -PercentComplete -1 @" vcpkg ($($StartDate.ToString('yyyy.MM.dd')) - $((($EndDate).AddSeconds(-1)).ToString('yyyy.MM.dd'))) --- @@ -351,7 +405,7 @@ vcpkg ($($StartDate.ToString('yyyy.MM.dd')) - $((($EndDate).AddSeconds(-1)).ToSt #### The following documentation has been updated: $(-join ($UpdatedDocumentation | ForEach-Object { - "- [TITLE]({0}){1}`n" -f $_.Path, (& { if ($_.New) { ' ***[NEW]***' } else { '' } }) + "- [TITLE]({0}){1}`n" -f $_.Path, ($(if ($_.New) { ' ***[NEW]***' } else { '' })) $_.Pulls | ForEach-Object { " - [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login @@ -375,8 +429,8 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { |---|---| $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - - if ($_.Pulls.Length -gt 1) { + + if ($_.Pulls.Length -gt 1 ) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { "[#{0}]({1})" -f $_.number, $_.html_url @@ -404,3 +458,5 @@ $(-join ($ChangedPorts | ForEach-Object { -- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") "@ | Out-File (Get-ChangelogFileName) + +Write-Progress -Activity 'Writing changelog file' -Completed From 243880ccfcc11b362b9a9fa3a1507ed0f635de7d Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 00:37:28 -0800 Subject: [PATCH 08/18] Remove whitespace --- scripts/Get-Changelog.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index ab053cbbe7b9ca..525a31d1133b18 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -32,12 +32,12 @@ Param ( [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, - + # The end date range (exclusive) [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$EndDate, - + # GitHub credentials (username and PAT) [Parameter(Mandatory=$False,ValueFromPipeline=$True)] [Credential()] @@ -429,7 +429,7 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { |---|---| $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - + if ($_.Pulls.Length -gt 1 ) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { From 0be60b83ddbfa7e30f395cedaad9099f8b7a5786 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 00:42:07 -0800 Subject: [PATCH 09/18] Documentation --- scripts/Get-Changelog.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 525a31d1133b18..3660d6deacb05e 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -24,7 +24,7 @@ using namespace System.Collections.Generic Get-Changelog -Credentials $cred .OUTPUTS A "CHANGELOG.md" file in the working directory. If the file already exists, - + suffix is added to the filename and a new file is created to prevent overwriting. #> [CmdletBinding(PositionalBinding=$True)] Param ( @@ -32,12 +32,12 @@ Param ( [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, - + # The end date range (exclusive) [Parameter(Mandatory=$True)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$EndDate, - + # GitHub credentials (username and PAT) [Parameter(Mandatory=$False,ValueFromPipeline=$True)] [Credential()] @@ -429,7 +429,7 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { |---|---| $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - + if ($_.Pulls.Length -gt 1 ) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { From 1b727d99bdafd0674c9b41d875fe3c4004034e76 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 00:48:34 -0800 Subject: [PATCH 10/18] Remove unneeded parens --- scripts/Get-Changelog.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 3660d6deacb05e..bb88de70475d30 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -371,7 +371,7 @@ function Get-ChangelogFileName() { "CHANGELOG$suffix.md" } -$PRFileMaps = (Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap) +$PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 From 5898d166f4afc92b5ab72bc8513a8e65693283b5 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 01:28:45 -0800 Subject: [PATCH 11/18] Correct regex match reference; Sort documentation by filename --- scripts/Get-Changelog.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index bb88de70475d30..cd81aea922d367 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -361,7 +361,7 @@ function Select-UpdatedPorts { function Get-ChangelogFileName() { $suffixes = Get-ChildItem -Path . | ForEach-Object { if (-not($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md')) { return } - if ($Matches.PSObject.Properties.Name -contains 'number') { $Matches.number } else { '0' } + if ($Matches['number']) { $Matches.number } else { '0' } } | Sort-Object $suffix = 0 @@ -375,7 +375,8 @@ $PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-Pull Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 -$UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object -Property 'New' -Descending +$sortSplat = @{ Property = @{ Expression = 'New'; Descending = $True }, @{ Expression = 'Path'; Descending = $False }} +$UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object @sortSplat $UpdatedInfrastructure = $PRFileMaps | Select-InfrastructurePullRequests $UpdatedPorts = $PRFileMaps | Select-UpdatedPorts $NewPorts = $UpdatedPorts | Where-Object { $_.New } From bb2d776e998a24fc39b6ee9d497fcbe43a8b6d57 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 01:29:49 -0800 Subject: [PATCH 12/18] Formatting --- scripts/Get-Changelog.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index cd81aea922d367..ca1749194fd3ba 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -360,7 +360,7 @@ function Select-UpdatedPorts { function Get-ChangelogFileName() { $suffixes = Get-ChildItem -Path . | ForEach-Object { - if (-not($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md')) { return } + if (-not ($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md')) { return } if ($Matches['number']) { $Matches.number } else { '0' } } | Sort-Object From 75566b94422e9ce25cb5308087b69d00d0459cf4 Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Sat, 2 Jan 2021 01:36:00 -0800 Subject: [PATCH 13/18] Formatting --- scripts/Get-Changelog.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index ca1749194fd3ba..46cf479afae776 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -375,7 +375,8 @@ $PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-Pull Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 -$sortSplat = @{ Property = @{ Expression = 'New'; Descending = $True }, @{ Expression = 'Path'; Descending = $False }} +$sortSplat = @{ Property = + @{ Expression = 'New'; Descending = $True }, @{ Expression = 'Path'; Descending = $False } } $UpdatedDocumentation = $PRFileMaps | Select-Documentation | Sort-Object @sortSplat $UpdatedInfrastructure = $PRFileMaps | Select-InfrastructurePullRequests $UpdatedPorts = $PRFileMaps | Select-UpdatedPorts From f2fa4df863e34ad1622da188348dbc24c9f76f1c Mon Sep 17 00:00:00 2001 From: Griffin Downs <35574547+grdowns@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:34:23 +0100 Subject: [PATCH 14/18] Apply suggestions from code review Co-authored-by: nicole mazzuca --- scripts/Get-Changelog.ps1 | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 46cf479afae776..7cea2abe7bdcb9 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -2,16 +2,16 @@ # We are not using Powershell >= 6.0, as the only supported debugger (vscode powershell extension) breaks on complex code. See: https://github.com/PowerShell/PowerShellEditorServices/issues/1295 # This code can be run on PowerShell Core on any platform, but it is recommend to debug this code in Windows PowerShell ISE unless debugging happens to "just work" on your machine. # Expect the fix to be out at around the end of 2020/beginning of 2021, at which point consider upgrading this script to PowerShell 7 the next time maintenance is necessary. -# -- Griffin Downs Dec 15, 2020 (@grdowns) +# -- Griffin Downs 2020-12-15 (@grdowns) using namespace System.Management.Automation using namespace System.Collections.Generic <# -.Synopsis +.SYNOPSIS Changelog generator for vcpkg. .DESCRIPTION - The changelog generator uses the GitHub Pull Request and Files API's to get + The changelog generator uses GitHub's Pull Request and Files API to get pull requests and their associated file changes over the provided date range. Then, the data is processed into buckets which are then presented to the user in a markdown file. @@ -29,17 +29,20 @@ using namespace System.Collections.Generic [CmdletBinding(PositionalBinding=$True)] Param ( # The begin date range (inclusive) - [Parameter(Mandatory=$True)] + [Parameter(Mandatory=$True, Position=0)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, # The end date range (exclusive) - [Parameter(Mandatory=$True)] + [Parameter(Mandatory, Position=1)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$EndDate, + + [Parameter(Mandatory=$True)] + [String]$OutFile, # GitHub credentials (username and PAT) - [Parameter(Mandatory=$False,ValueFromPipeline=$True)] + [Parameter()] [Credential()] [PSCredential]$Credentials ) @@ -57,11 +60,17 @@ if (-not $Credentials) { } function Get-AuthHeader() { + [CmdletBinding()] + Param( + [Parameter(Mandatory=$True)] + [Credential()] + [PSCredential]$Credentials + ) @{ Authorization = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( - ('{0}:{1}' -f $Credentials.UserName, $Credentials.GetNetworkCredential().Password))) } + "$($Credentials.UserName):$($Credentials.GetNetworkCredential().Password)" } } -$response = Invoke-WebRequest -uri 'https://api.github.com' -Headers ($Credentials | Get-AuthHeader) +$response = Invoke-WebRequest -uri 'https://api.github.com' -Headers (Get-AuthHeader $Credentials) if ('X-OAuth-Scopes' -notin $response.Headers.Keys) { throw [System.ArgumentException]::new( "Cannot validate argument on parameter 'Credentials'. Incorrect GitHub credentials" @@ -72,7 +81,11 @@ if ('X-OAuth-Scopes' -notin $response.Headers.Keys) { function Get-MergedPullRequests { [CmdletBinding()] [OutputType([Object[]])] - Param () + Param( + [Parameter(Mandatory=$True)] + [Credential()] + [PSCredential]$Credentials + ) Begin { $RequestSplat = @{ Uri = 'https://api.github.com/repos/Microsoft/vcpkg/pulls' @@ -89,8 +102,7 @@ function Get-MergedPullRequests { $DeltaEpochStart = ($Epoch - $StartDate).Ticks $ProgressSplat = @{ - Activity = 'Searching for merged Pull Requests in date range: {0} - {1}' -f - $StartDate.ToString('yyyy.MM.dd'), $EndDate.ToString('yyyy.MM.dd') + Activity = "Searching for merged Pull Requests in date range: $($StartDate.ToString('yyyy-MM-dd')) - $($EndDate.ToString('yyyy-MM-dd'))" PercentComplete = 0 } @@ -98,12 +110,12 @@ function Get-MergedPullRequests { $writeProgress = { $ProgressSplat.PercentComplete = 100 * ($Epoch - $_.updated_at).Ticks / $DeltaEpochStart - Write-Progress @ProgressSplat -Status ('Current item date: {0}' -f $_.updated_at.ToString('yyyy.MM.dd')) + Write-Progress @ProgressSplat -Status "Current item date: $($_.updated_at.ToString('yyyy-MM-dd'))" } } Process { while ($True) { - $response = Invoke-WebRequest -Headers (Get-AuthHeader) @RequestSplat | ConvertFrom-Json + $response = Invoke-WebRequest -Headers (Get-AuthHeader $Credentials) @RequestSplat | ConvertFrom-Json foreach ($_ in $response) { foreach ($x in 'created_at', 'merged_at', 'updated_at', 'closed_at') { From 1bcc52a8205e2e56eb9f378548934b27cdd01c29 Mon Sep 17 00:00:00 2001 From: Griffin Downs <35574547+grdowns@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:35:04 +0100 Subject: [PATCH 15/18] Update scripts/Get-Changelog.ps1 Co-authored-by: nicole mazzuca --- scripts/Get-Changelog.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 7cea2abe7bdcb9..3d6880fe441b75 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -13,8 +13,8 @@ using namespace System.Collections.Generic .DESCRIPTION The changelog generator uses GitHub's Pull Request and Files API to get pull requests and their associated file changes over the provided date range. - Then, the data is processed into buckets which are then presented to the user - in a markdown file. + Then, the data is processed into buckets which are presented to the user + as a markdown file. .EXAMPLE Get-Changelog .EXAMPLE From 4818e155e69c8082f32626b7a172dfde3b1ff87d Mon Sep 17 00:00:00 2001 From: Griffin Downs Date: Thu, 11 Feb 2021 23:40:36 +0100 Subject: [PATCH 16/18] Fix syntax errors; Add credentials as param and args; output to OutFile --- scripts/Get-Changelog.ps1 | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 3d6880fe441b75..d8178bad493704 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -67,7 +67,7 @@ function Get-AuthHeader() { [PSCredential]$Credentials ) @{ Authorization = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( - "$($Credentials.UserName):$($Credentials.GetNetworkCredential().Password)" } + "$($Credentials.UserName):$($Credentials.GetNetworkCredential().Password)")) } } $response = Invoke-WebRequest -uri 'https://api.github.com' -Headers (Get-AuthHeader $Credentials) @@ -149,7 +149,10 @@ function Get-PullRequestFileMap { [OutputType([PRFileMap[]])] Param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True)] - [Object]$Pull + [Object]$Pull, + [Parameter(Mandatory=$True)] + [Credential()] + [PSCredential]$Credentials ) Begin { $Pulls = [List[Object]]::new() @@ -186,7 +189,7 @@ function Get-PullRequestFileMap { do { $requestSplat.Body.page++ - $response = Invoke-WebRequest -Headers (Get-AuthHeader) @requestSplat | ConvertFrom-Json + $response = Invoke-WebRequest -Headers (Get-AuthHeader $Credentials) @requestSplat | ConvertFrom-Json $response } until ($response.Length -lt $requestSplat.Body.per_page) @@ -370,20 +373,7 @@ function Select-UpdatedPorts { } } -function Get-ChangelogFileName() { - $suffixes = Get-ChildItem -Path . | ForEach-Object { - if (-not ($_ -match '^CHANGELOG([\-](?[0-9]+))?\.md')) { return } - if ($Matches['number']) { $Matches.number } else { '0' } - } | Sort-Object - - $suffix = 0 - while ([String]$suffix -in $suffixes) { $suffix++ } - - $suffix = if ($suffix) { "-$suffix" } else { '' } - "CHANGELOG$suffix.md" -} - -$PRFileMaps = Get-MergedPullRequests | Sort-Object -Property 'number' | Get-PullRequestFileMap +$PRFileMaps = (Get-MergedPullRequests $Credentials) | Sort-Object -Property 'number' | Get-PullRequestFileMap -Credentials $Credentials Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 @@ -471,6 +461,6 @@ $(-join ($ChangedPorts | ForEach-Object { -- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") -"@ | Out-File (Get-ChangelogFileName) +"@ | Out-File -FilePath $OutFile Write-Progress -Activity 'Writing changelog file' -Completed From 9161eaecf84d1393c846adc26a3e374011437fb3 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 23 Feb 2022 20:50:56 -0800 Subject: [PATCH 17/18] Fix many many bugs in the changelog generation script: 84: Pass StartDate and EndDate to Get-MergedPullRequests instead of special casing only Credentials 109+130: Fix calculating negative progress caused by seeing PRs in the future because GitHub returns times in UTC 268: Actually make filtering for infrastructure PRs functional 303: Fix extraction of port-version from vcpkg.json. This really should be handled by diffing baseline.json in the future. 374-382: Fix expression ordering and casting problem which prevented non-CONTROL ports from ever being considered "new" Also skip emitting headers for empty blocks, update and sort current triplet list, and move infrastructure bits below port modifications. Example output: vcpkg (2022.02.19 - 2022.02.22) --- #### Total port count: #### Total port count per triplet (tested): |triplet|ports available| |---|---| |x86-windows|NUM| |**x64-windows**|NUM| |x64-windows-static|NUM| |x64-windows-static-md|NUM| |x64-uwp|NUM| |arm64-windows|NUM| |arm-uwp|NUM| |**x64-osx**|NUM| |**x64-linux**|NUM|
The following 2 ports have been added: |port|version| |---|---| |[libcurl-simple-https](https://github.com/microsoft/vcpkg/pull/22917)|2022-02-14 |[triton](https://github.com/microsoft/vcpkg/pull/23111)|0.9
The following 18 ports have been updated: - polyhook2 `2022-02-06#0` -> `2022-02-21#0` - [(#23203)](https://github.com/microsoft/vcpkg/pull/23203) [polyhook2] Update to latest (2022-02-21) (by @acidicoala) - graphviz `2.49.1#1` -> `2.49.1#2` - [(#23148)](https://github.com/microsoft/vcpkg/pull/23148) [graphviz] Fix tools (by @Ace314159) - itk `5.1.0#7` -> `5.2.1#0` - [(#23158)](https://github.com/microsoft/vcpkg/pull/23158) [ITK] update to v5.2.1 (by @Adela0814) - qhull `8.0.2#2` -> `8.0.2#3` - [(#23129)](https://github.com/microsoft/vcpkg/pull/23129) [qhull] Fix copyright, pc files, cmake usage (by @dg0yt) - tgui `2021-04-19#2` -> `2021-04-19#3` - [(#23211)](https://github.com/microsoft/vcpkg/pull/23211) [tgui] fix absolute paths (by @autoantwort) - json-dto `0.3.0#0` -> `0.3.1#0` - [(#23224)](https://github.com/microsoft/vcpkg/pull/23224) [json-dto] Update to 0.3.1 (by @eao197) - leveldb `1.22#4` -> `1.22#5` - [(#23180)](https://github.com/microsoft/vcpkg/pull/23180) [leveldb] Fix homepage (by @MarcoFalke) - openxr-loader `1.0.22#0` -> `1.0.22#1` - [(#23191)](https://github.com/microsoft/vcpkg/pull/23191) [openxr-loader] Fix build failure in world rebuild CI. (by @Hoikas) - ngspice `35#1` -> `35#2` - [(#23151)](https://github.com/microsoft/vcpkg/pull/23151) [ngspice] Fix error C2065 (by @Cheney-W) - openmvg `2.0#1` -> `2.0#2` - [(#23114)](https://github.com/microsoft/vcpkg/pull/23114) [cereal] Update to 1.3.1 (by @mapret) - lazy-importer `2021-10-23#0` -> `2022-02-09#0` - [(#23192)](https://github.com/microsoft/vcpkg/pull/23192) [lazy-importer] Update to 2022-02-09 (by @Thomas1664) - gstreamer `1.19.2#3` -> `1.19.2#4` - [(#23125)](https://github.com/microsoft/vcpkg/pull/23125) [gstreamer] Support arm-windows and add features (by @JackBoosY) - charls `2.2.0#2` -> `2.3.4#0` - [(#23189)](https://github.com/microsoft/vcpkg/pull/23189) [charls] Update to 2.3.4 (by @Thomas1664) - arrow `7.0.0#0` -> `7.0.0#1` - [(#23188)](https://github.com/microsoft/vcpkg/pull/23188) [arrow] add plasma support for non Windows platforms (by @fran6co) - trantor `1.5.4#0` -> `1.5.5#0` - [(#23182)](https://github.com/microsoft/vcpkg/pull/23182) [trantor] Update to 1.5.5 (by @an-tao) - capstone `4.0.2#2` -> `4.0.2#3` - [(#23122)](https://github.com/microsoft/vcpkg/pull/23122) [capstone] Use static runtime if capstone wants to be statically linked (by @illera88) - gainput `1.0.0#4` -> `1.0.0#5` - [(#23219)](https://github.com/microsoft/vcpkg/pull/23219) [gainput] Support Linux (by @JackBoosY) - cereal `1.3.0#1` -> `1.3.1#0` - [(#23114)](https://github.com/microsoft/vcpkg/pull/23114) [cereal] Update to 1.3.1 (by @mapret)
The following additional changes have been made to vcpkg's infrastructure: - [(#23045)](https://github.com/microsoft/vcpkg/pull/23045) [vcpkg docs] Update ko_KR translation (by @jnooree) - [(#23181)](https://github.com/microsoft/vcpkg/pull/23181) [vcpkg doc] Fixes typo in vcpkg_download_distfile.cmake (by @acd1034)
-- vcpkg team vcpkg@microsoft.com Thu, 24 February 00:29:57 -0800 --- scripts/Get-Changelog.ps1 | 95 ++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index d8178bad493704..8975c144e11c71 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -32,7 +32,7 @@ Param ( [Parameter(Mandatory=$True, Position=0)] [ValidateScript({$_ -le (Get-Date)})] [DateTime]$StartDate, - + # The end date range (exclusive) [Parameter(Mandatory, Position=1)] [ValidateScript({$_ -le (Get-Date)})] @@ -40,14 +40,13 @@ Param ( [Parameter(Mandatory=$True)] [String]$OutFile, - + # GitHub credentials (username and PAT) [Parameter()] [Credential()] [PSCredential]$Credentials ) - Set-StrictMode -Version 2 if (-not $Credentials) { @@ -82,6 +81,15 @@ function Get-MergedPullRequests { [CmdletBinding()] [OutputType([Object[]])] Param( + [Parameter(Mandatory=$True, Position=0)] + [ValidateScript({$_ -le (Get-Date)})] + [DateTime]$StartDate, + + # The end date range (exclusive) + [Parameter(Mandatory, Position=1)] + [ValidateScript({$_ -le (Get-Date)})] + [DateTime]$EndDate, + [Parameter(Mandatory=$True)] [Credential()] [PSCredential]$Credentials @@ -98,7 +106,7 @@ function Get-MergedPullRequests { page = 1 } } - $Epoch = Get-Date + $Epoch = Get-Date -AsUTC $DeltaEpochStart = ($Epoch - $StartDate).Ticks $ProgressSplat = @{ @@ -119,7 +127,9 @@ function Get-MergedPullRequests { foreach ($_ in $response) { foreach ($x in 'created_at', 'merged_at', 'updated_at', 'closed_at') { - if ($_.$x) { $_.$x = [DateTime]::Parse($_.$x) } + if ($_.$x) { $_.$x = [DateTime]::Parse($_.$x, + [System.Globalization.CultureInfo]::InvariantCulture, + [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal) } } if (-not $_.merged_at) { continue } @@ -255,9 +265,11 @@ function Select-InfrastructurePullRequests { [PRFileMap]$PRFileMap ) Process { - switch -Wildcard ($PRFileMap.Files | Get-Member 'filename') { + switch -Wildcard ($PRFileMap.Files | Foreach-Object {$_.filename}) { "docs/*" { continue } "ports/*" { continue } + "versions/*" { continue } + "scripts/ci.baseline.txt" { continue } Default { return $PRFileMap.Pull } } } @@ -288,7 +300,7 @@ function Select-Version { '(?^[\+|\-]|)(?Version|[\+|\-]Port-Version):\s(?\S+)' } 'vcpkg.json' { - '(?^[\+|\-]|)\s*\"(?version-string|port-version)\":\s\"(?.+)\"' + '(?^[\+|\-]|)\s*(\"(?version|version-date|version-string|version-semver)\":\s\"(?.+)\"|\"(?port-version)\":\s(?.+))' } Default { return } } @@ -359,23 +371,23 @@ function Select-UpdatedPorts { $versionFiles = $_.Value.VersionFiles if (-not ($versionChange = $versionFiles | Select-Version)) { return } - function Find-File($x) { $versionFiles | Where-Object { $_.filename -like "*$x" } } + function Find-File($x) { [bool]($versionFiles | Where-Object { $_.filename -like "*$x" }) } function Find-NewFile($x) - { $versionFiles | Where-Object { $_.filename -like "*$x" -and $_.status -eq 'added' } } + { [bool]($versionFiles | Where-Object { $_.filename -like "*$x" -and $_.status -eq 'added' }) } [PortUpdate]@{ Port = $_.Key Pulls = $_.Value.Pulls Version = $versionChange - New = Find-NewFile 'CONTROL' -or (-not (Find-File 'CONTROL') -and (Find-NewFile 'vcpkg.json')) + New = (Find-NewFile 'CONTROL') -or (-not (Find-File 'CONTROL') -and (Find-NewFile 'vcpkg.json')) } } } } -$PRFileMaps = (Get-MergedPullRequests $Credentials) | Sort-Object -Property 'number' | Get-PullRequestFileMap -Credentials $Credentials - -Write-Progress -Activity 'Selecting updates from pull request files' -PercentComplete -1 +$MergedPRs = Get-MergedPullRequests -StartDate $StartDate -EndDate $EndDate -Credentials $Credentials +$MergedPRsSorted = $MergedPRs | Sort-Object -Property 'number' +$PRFileMaps = $MergedPRsSorted | Get-PullRequestFileMap -Credentials $Credentials $sortSplat = @{ Property = @{ Expression = 'New'; Descending = $True }, @{ Expression = 'Path'; Descending = $False } } @@ -388,24 +400,28 @@ $ChangedPorts = $UpdatedPorts | Where-Object { -not $_.New } Write-Progress -Activity 'Selecting updates from pull request files' -Completed Write-Progress -Activity 'Writing changelog file' -PercentComplete -1 -@" + +$output = @" vcpkg ($($StartDate.ToString('yyyy.MM.dd')) - $((($EndDate).AddSeconds(-1)).ToString('yyyy.MM.dd'))) --- #### Total port count: #### Total port count per triplet (tested): |triplet|ports available| |---|---| -|**x64-windows**|NUM| |x86-windows|NUM| +|**x64-windows**|NUM| |x64-windows-static|NUM| -|**x64-osx**|NUM| -|**x64-linux**|NUM| -|arm64-windows|NUM| +|x64-windows-static-md|NUM| |x64-uwp|NUM| +|arm64-windows|NUM| |arm-uwp|NUM| +|**x64-osx**|NUM| +|**x64-linux**|NUM| -#### The following commands and options have been updated: +"@ +if ($UpdatedDocumentation) { + $output += @" #### The following documentation has been updated: $(-join ($UpdatedDocumentation | ForEach-Object { @@ -416,16 +432,11 @@ $(-join ($UpdatedDocumentation | ForEach-Object { } })) -#### The following *remarkable* changes have been made to vcpkg's infrastructure: - -
-The following additional changes have been made to vcpkg's infrastructure: - -$(-join ($UpdatedInfrastructure | ForEach-Object { - "- [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login -})) -
+"@ +} +if ($NewPorts) { + $output += @"
The following $($NewPorts.Length) ports have been added: @@ -433,7 +444,7 @@ $(-join ($UpdatedInfrastructure | ForEach-Object { |---|---| $(-join ($NewPorts | ForEach-Object { "|[{0}]({1})" -f $_.Port, $_.Pulls[0].html_url - + if ($_.Pulls.Length -gt 1 ) { '' $_.Pulls[1..($_.Pulls.Length - 1)] | ForEach-Object { @@ -446,6 +457,11 @@ $(-join ($NewPorts | ForEach-Object { }))
+"@ +} + +if ($ChangedPorts) { + $output += @"
The following $($ChangedPorts.Length) ports have been updated: @@ -460,7 +476,26 @@ $(-join ($ChangedPorts | ForEach-Object { }))
+"@ +} + +if ($UpdatedInfrastructure) { + $output += @" +
+The following additional changes have been made to vcpkg's infrastructure: + +$(-join ($UpdatedInfrastructure | ForEach-Object { + "- [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login +})) +
+ +"@ +} + +$output += @" -- vcpkg team vcpkg@microsoft.com $(Get-Date -UFormat "%a, %d %B %T %Z00") -"@ | Out-File -FilePath $OutFile +"@ + +Set-Content -Value $Output -Path $OutFile Write-Progress -Activity 'Writing changelog file' -Completed From b7f0c30f73f568963242b24211ba9416e8672de5 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 24 Feb 2022 01:09:10 -0800 Subject: [PATCH 18/18] Fix random "TITLE" in docs output. --- scripts/Get-Changelog.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Get-Changelog.ps1 b/scripts/Get-Changelog.ps1 index 8975c144e11c71..68f02957e3b6a8 100644 --- a/scripts/Get-Changelog.ps1 +++ b/scripts/Get-Changelog.ps1 @@ -425,7 +425,8 @@ if ($UpdatedDocumentation) { #### The following documentation has been updated: $(-join ($UpdatedDocumentation | ForEach-Object { - "- [TITLE]({0}){1}`n" -f $_.Path, ($(if ($_.New) { ' ***[NEW]***' } else { '' })) + $PathWithoutDocs = ([string]$_.Path).Remove(0, 5) # 'docs/' + "- [{0}]({0}){1}`n" -f $PathWithoutDocs, $_.Path, ($(if ($_.New) { ' ***[NEW]***' } else { '' })) $_.Pulls | ForEach-Object { " - [(#{0})]({1}) {2} (by @{3})`n" -f $_.number, $_.html_url, $_.title, $_.user.login