From 03c714e0e753206ef2aa98d8f4f7fb56de5dc00b Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 12:27:02 -0700 Subject: [PATCH 1/6] Add release script --- eng/scripts/Prepare-Release.ps1 | 105 ++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 eng/scripts/Prepare-Release.ps1 diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 new file mode 100644 index 000000000000..63f03dc938d1 --- /dev/null +++ b/eng/scripts/Prepare-Release.ps1 @@ -0,0 +1,105 @@ +param($package) + +$repoRoot = Resolve-Path "$PSScriptRoot/../.."; + +$serviceDirectory = (Get-ChildItem "$repoRoot/sdk" -Directory -Recurse -Depth 2 -Filter $package).Parent.Name + +Write-Host "Source directory $serviceDirectory" + +$existing = Invoke-WebRequest "https://api.nuget.org/v3-flatcontainer/$($package.ToLower())/index.json" | ConvertFrom-Json; + +. ${repoRoot}\eng\common\scripts\SemVer.ps1 + +$libraryType = "preview"; +$latestVersion = "unknown"; +foreach ($existingVersion in $existing.versions) +{ + $parsedVersion = [AzureEngSemanticVersion]::new($existingVersion) + if (!$packageOldSemVer.IsPrerelease) + { + $libraryType = "GA" + } + $latestVersion = $existingVersion; +} + +$latestVersion = $existing.versions[$existing.versions.Count - 1]; + +Write-Host "Latest released version $latestVersion, library type $libraryType" + +$newVersion = Read-Host -Prompt 'Input the new version' + +$releaseType = "None"; +$parsedNewVersion = [AzureEngSemanticVersion]::new($newVersion) +if ($parsedNewVersion.Major -ne $parsedVersion.Major) +{ + $releaseType = "Major" +} +elseif ($parsedNewVersion.Minor -ne $parsedVersion.Minor) +{ + $releaseType = "Minor" +} +elseif ($parsedNewVersion.Patch -ne $parsedVersion.Patch) +{ + $releaseType = "Bugfix" +} +elseif ($parsedNewVersion.IsPrerelease) +{ + $releaseType = "Bugfix" +} + +Write-Host "Detected released type $releaseType" + +& "$repoRoot\eng\scripts\Update-PkgVersion.ps1" -ServiceDirectory $serviceDirectory -PackageName $package -NewVersionString $newVersion + +$date = Get-Date +$month = $date.ToString("MMMM") +if ($date.Day -gt 15) +{ + $month = $date.AddMonths(1).ToString("MMMM") +} + +Write-Host "Assuming release is in $month" + +$commonParameter = @("--organization", "https://dev.azure.com/azure-sdk", "-o", "json", "--only-show-errors") + +$workItems = az boards query @commonParameter --project Release --wiql "SELECT [ID], [State], [Iteration Path], [Title] FROM WorkItems WHERE [State] <> 'Closed' AND [Iteration Path] under 'Release\2020\$month' AND [Title] contains '.NET'" | ConvertFrom-Json; + +$matchedWorkItems = @(); + +Write-Host "The following issues exist:" +foreach ($item in $workItems) +{ + $id = $item.fields."System.ID"; + $title = $item.fields."System.Title"; + $path = $item.fields."System.IterationPath"; + Write-Host "$id - $path - $title" +} + +$issueId = Read-Host -Prompt 'Input the issue ID' + +$fields = @{ + "Permalink usetag"="https://github.com/Azure/azure-sdk-for-net/sdk/$serviceDirectory/$package/README.md"; + "Package Registry Permalink"="https://nuget.org/packages/$package/$newVersion"; + "Library Type"=$libraryType; + "Release Type"=$releaseType; + "Version Number"=$newVersion; +} + +Write-Host "Going to set the following fields:" + +foreach ($field in $fields.Keys) +{ + Write-Host " $field $($fields[$field])" +} + +$decision = $Host.UI.PromptForChoice('Updating work item', 'Are you sure you want to proceed?', @('&Yes'; '&No'), 0) + +if ($decision -eq 0) +{ + foreach ($field in $fields.Keys) + { + az boards work-item update @commonParameter --id $issueId -f "$field=$($fields[$field])" > $null + } + + Write-Host "Updated https://dev.azure.com/azure-sdk/Release/_workitems/edit/$issueId" +} \ No newline at end of file From f7e0c6de0b1ea72d2d126b37268a93b863d61e4b Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 12:32:11 -0700 Subject: [PATCH 2/6] Fixes --- eng/scripts/Prepare-Release.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 index 63f03dc938d1..d7c3b9f21c77 100644 --- a/eng/scripts/Prepare-Release.ps1 +++ b/eng/scripts/Prepare-Release.ps1 @@ -24,6 +24,7 @@ foreach ($existingVersion in $existing.versions) $latestVersion = $existing.versions[$existing.versions.Count - 1]; +Write-Host Write-Host "Latest released version $latestVersion, library type $libraryType" $newVersion = Read-Host -Prompt 'Input the new version' @@ -47,8 +48,12 @@ elseif ($parsedNewVersion.IsPrerelease) $releaseType = "Bugfix" } +Write-Host Write-Host "Detected released type $releaseType" +Write-Host +Write-Host "Updating versions" + & "$repoRoot\eng\scripts\Update-PkgVersion.ps1" -ServiceDirectory $serviceDirectory -PackageName $package -NewVersionString $newVersion $date = Get-Date @@ -57,7 +62,7 @@ if ($date.Day -gt 15) { $month = $date.AddMonths(1).ToString("MMMM") } - +Write-Host Write-Host "Assuming release is in $month" $commonParameter = @("--organization", "https://dev.azure.com/azure-sdk", "-o", "json", "--only-show-errors") @@ -66,6 +71,7 @@ $workItems = az boards query @commonParameter --project Release --wiql "SELECT [ $matchedWorkItems = @(); +Write-Host Write-Host "The following issues exist:" foreach ($item in $workItems) { @@ -85,17 +91,19 @@ $fields = @{ "Version Number"=$newVersion; } +Write-Host Write-Host "Going to set the following fields:" foreach ($field in $fields.Keys) { - Write-Host " $field $($fields[$field])" + Write-Host " $field = $($fields[$field])" } $decision = $Host.UI.PromptForChoice('Updating work item', 'Are you sure you want to proceed?', @('&Yes'; '&No'), 0) if ($decision -eq 0) { + az boards work-item update @commonParameter --id $issueId --state Active > $null foreach ($field in $fields.Keys) { az boards work-item update @commonParameter --id $issueId -f "$field=$($fields[$field])" > $null From cd53ff513b75fd8287415190a7def37446536085 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 12:48:01 -0700 Subject: [PATCH 3/6] Print changelog --- eng/scripts/Prepare-Release.ps1 | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 index d7c3b9f21c77..8f073bd63276 100644 --- a/eng/scripts/Prepare-Release.ps1 +++ b/eng/scripts/Prepare-Release.ps1 @@ -2,14 +2,16 @@ param($package) $repoRoot = Resolve-Path "$PSScriptRoot/../.."; -$serviceDirectory = (Get-ChildItem "$repoRoot/sdk" -Directory -Recurse -Depth 2 -Filter $package).Parent.Name +. ${repoRoot}\eng\common\scripts\SemVer.ps1 +. ${repoRoot}\eng\common\scripts\ChangeLog-Operations.ps1 + +$packageDirectory = Get-ChildItem "$repoRoot/sdk" -Directory -Recurse -Depth 2 -Filter $package +$serviceDirectory = ($packageDirectory).Parent.Name Write-Host "Source directory $serviceDirectory" $existing = Invoke-WebRequest "https://api.nuget.org/v3-flatcontainer/$($package.ToLower())/index.json" | ConvertFrom-Json; -. ${repoRoot}\eng\common\scripts\SemVer.ps1 - $libraryType = "preview"; $latestVersion = "unknown"; foreach ($existingVersion in $existing.versions) @@ -110,4 +112,14 @@ if ($decision -eq 0) } Write-Host "Updated https://dev.azure.com/azure-sdk/Release/_workitems/edit/$issueId" -} \ No newline at end of file +} + +$changeLogEntry = Get-ChangeLogEntry -ChangeLogLocation "$packageDirectory/CHANGELOG.md" -VersionString $newVersion + +$githubAnchor = $changeLogEntry.ReleaseTitle.Replace("## ", "").Replace(".", "").Replace("(", "").Replace(")", "").Replace(" ", "-") +Write-Host +Write-Host "Snippet for the centralized CHANGELOG:" +Write-Host "dotnet add package $package --version $newVersion" +Write-Host "### $package [Changelog](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/$serviceDirectory/$package/CHANGELOG.md#$githubAnchor)" +$changeLogEntry.ReleaseContent | Write-Host + From 63895d4b817f5ca415e80067c905f75221838bfe Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 12:49:21 -0700 Subject: [PATCH 4/6] Colors --- eng/scripts/Prepare-Release.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 index 8f073bd63276..22a335eea384 100644 --- a/eng/scripts/Prepare-Release.ps1 +++ b/eng/scripts/Prepare-Release.ps1 @@ -27,7 +27,7 @@ foreach ($existingVersion in $existing.versions) $latestVersion = $existing.versions[$existing.versions.Count - 1]; Write-Host -Write-Host "Latest released version $latestVersion, library type $libraryType" +Write-Host "Latest released version $latestVersion, library type $libraryType" -ForegroundColor Green $newVersion = Read-Host -Prompt 'Input the new version' @@ -51,10 +51,10 @@ elseif ($parsedNewVersion.IsPrerelease) } Write-Host -Write-Host "Detected released type $releaseType" +Write-Host "Detected released type $releaseType" -ForegroundColor Green Write-Host -Write-Host "Updating versions" +Write-Host "Updating versions" -ForegroundColor Green & "$repoRoot\eng\scripts\Update-PkgVersion.ps1" -ServiceDirectory $serviceDirectory -PackageName $package -NewVersionString $newVersion @@ -65,7 +65,7 @@ if ($date.Day -gt 15) $month = $date.AddMonths(1).ToString("MMMM") } Write-Host -Write-Host "Assuming release is in $month" +Write-Host "Assuming release is in $month" -ForegroundColor Green $commonParameter = @("--organization", "https://dev.azure.com/azure-sdk", "-o", "json", "--only-show-errors") @@ -94,7 +94,7 @@ $fields = @{ } Write-Host -Write-Host "Going to set the following fields:" +Write-Host "Going to set the following fields:" -ForegroundColor Green foreach ($field in $fields.Keys) { @@ -118,7 +118,7 @@ $changeLogEntry = Get-ChangeLogEntry -ChangeLogLocation "$packageDirectory/CHANG $githubAnchor = $changeLogEntry.ReleaseTitle.Replace("## ", "").Replace(".", "").Replace("(", "").Replace(")", "").Replace(" ", "-") Write-Host -Write-Host "Snippet for the centralized CHANGELOG:" +Write-Host "Snippet for the centralized CHANGELOG:" -ForegroundColor Green Write-Host "dotnet add package $package --version $newVersion" Write-Host "### $package [Changelog](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/$serviceDirectory/$package/CHANGELOG.md#$githubAnchor)" $changeLogEntry.ReleaseContent | Write-Host From 534d947ae99b4760766e725bf5a12f0118a6a912 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 13:27:52 -0700 Subject: [PATCH 5/6] Fuzzy match issues --- eng/scripts/Prepare-Release.ps1 | 104 ++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 index 22a335eea384..04f3cdc00928 100644 --- a/eng/scripts/Prepare-Release.ps1 +++ b/eng/scripts/Prepare-Release.ps1 @@ -1,5 +1,76 @@ param($package) + +function Get-LevenshteinDistance { + <# + .SYNOPSIS + Get the Levenshtein distance between two strings. + .DESCRIPTION + The Levenshtein Distance is a way of quantifying how dissimilar two strings (e.g., words) are to one another by counting the minimum number of operations required to transform one string into the other. + .EXAMPLE + Get-LevenshteinDistance 'kitten' 'sitting' + .LINK + http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.23 + http://en.wikipedia.org/wiki/Edit_distance + https://communary.wordpress.com/ + https://github.com/gravejester/Communary.PASM + .NOTES + Author: Øyvind Kallstad + Date: 07.11.2014 + Version: 1.0 + #> + [CmdletBinding()] + param( + [Parameter(Position = 0)] + [string]$String1, + + [Parameter(Position = 1)] + [string]$String2, + + # Makes matches case-sensitive. By default, matches are not case-sensitive. + [Parameter()] + [switch] $CaseSensitive, + + # A normalized output will fall in the range 0 (perfect match) to 1 (no match). + [Parameter()] + [switch] $NormalizeOutput + ) + + if (-not($CaseSensitive)) { + $String1 = $String1.ToLowerInvariant() + $String2 = $String2.ToLowerInvariant() + } + + $d = New-Object 'Int[,]' ($String1.Length + 1), ($String2.Length + 1) + for ($i = 0; $i -le $d.GetUpperBound(0); $i++) { + $d[$i,0] = $i + } + + for ($i = 0; $i -le $d.GetUpperBound(1); $i++) { + $d[0,$i] = $i + } + + for ($i = 1; $i -le $d.GetUpperBound(0); $i++) { + for ($j = 1; $j -le $d.GetUpperBound(1); $j++) { + $cost = [Convert]::ToInt32((-not($String1[$i–1] -ceq $String2[$j–1]))) + $min1 = $d[($i–1),$j] + 1 + $min2 = $d[$i,($j–1)] + 1 + $min3 = $d[($i–1),($j–1)] + $cost + $d[$i,$j] = [Math]::Min([Math]::Min($min1,$min2),$min3) + } + } + + $distance = ($d[$d.GetUpperBound(0),$d.GetUpperBound(1)]) + + if ($NormalizeOutput) { + return (1 – ($distance) / ([Math]::Max($String1.Length,$String2.Length))) + } + + else { + return $distance + } +} + $repoRoot = Resolve-Path "$PSScriptRoot/../.."; . ${repoRoot}\eng\common\scripts\SemVer.ps1 @@ -12,24 +83,30 @@ Write-Host "Source directory $serviceDirectory" $existing = Invoke-WebRequest "https://api.nuget.org/v3-flatcontainer/$($package.ToLower())/index.json" | ConvertFrom-Json; -$libraryType = "preview"; +$libraryType = "Preview"; $latestVersion = "unknown"; foreach ($existingVersion in $existing.versions) { $parsedVersion = [AzureEngSemanticVersion]::new($existingVersion) - if (!$packageOldSemVer.IsPrerelease) + if (!$parsedVersion.IsPrerelease) { $libraryType = "GA" } + $latestVersion = $existingVersion; } -$latestVersion = $existing.versions[$existing.versions.Count - 1]; +$currentProjectVersion = ([xml](Get-Content "$packageDirectory/src/*.csproj")).Project.PropertyGroup.Version Write-Host Write-Host "Latest released version $latestVersion, library type $libraryType" -ForegroundColor Green -$newVersion = Read-Host -Prompt 'Input the new version' +$newVersion = Read-Host -Prompt "Input the new version or press Enter to use use current project version '$currentProjectVersion'" + +if (!$newVersion) +{ + $newVersion = $currentProjectVersion; +} $releaseType = "None"; $parsedNewVersion = [AzureEngSemanticVersion]::new($newVersion) @@ -71,10 +148,8 @@ $commonParameter = @("--organization", "https://dev.azure.com/azure-sdk", "-o", $workItems = az boards query @commonParameter --project Release --wiql "SELECT [ID], [State], [Iteration Path], [Title] FROM WorkItems WHERE [State] <> 'Closed' AND [Iteration Path] under 'Release\2020\$month' AND [Title] contains '.NET'" | ConvertFrom-Json; -$matchedWorkItems = @(); - Write-Host -Write-Host "The following issues exist:" +Write-Host "The following work items exist:" foreach ($item in $workItems) { $id = $item.fields."System.ID"; @@ -83,7 +158,16 @@ foreach ($item in $workItems) Write-Host "$id - $path - $title" } -$issueId = Read-Host -Prompt 'Input the issue ID' +# Sort using fuzzy match +$workItems = $workItems | Sort-Object -property @{Expression = { Get-LevenshteinDistance $_.fields."System.Title" $package -NormalizeOutput }} +$mostProbable = $workItems | Select-Object -Last 1 + +$issueId = Read-Host -Prompt "Input the work item ID or press Enter to use '$($mostProbable.fields."System.ID") - $($mostProbable.fields."System.Title")'" + +if (!$issueId) +{ + $issueId = $mostProbable.fields."System.ID" +} $fields = @{ "Permalink usetag"="https://github.com/Azure/azure-sdk-for-net/sdk/$serviceDirectory/$package/README.md"; @@ -101,7 +185,7 @@ foreach ($field in $fields.Keys) Write-Host " $field = $($fields[$field])" } -$decision = $Host.UI.PromptForChoice('Updating work item', 'Are you sure you want to proceed?', @('&Yes'; '&No'), 0) +$decision = $Host.UI.PromptForChoice("Updating work item https://dev.azure.com/azure-sdk/Release/_workitems/edit/$issueId", 'Are you sure you want to proceed?', @('&Yes'; '&No'), 0) if ($decision -eq 0) { @@ -110,8 +194,6 @@ if ($decision -eq 0) { az boards work-item update @commonParameter --id $issueId -f "$field=$($fields[$field])" > $null } - - Write-Host "Updated https://dev.azure.com/azure-sdk/Release/_workitems/edit/$issueId" } $changeLogEntry = Get-ChangeLogEntry -ChangeLogLocation "$packageDirectory/CHANGELOG.md" -VersionString $newVersion From 16471304ec43c0396ab9f0e08d8589926a33d809 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 28 Aug 2020 13:33:47 -0700 Subject: [PATCH 6/6] Feedback --- eng/scripts/Prepare-Release.ps1 | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/eng/scripts/Prepare-Release.ps1 b/eng/scripts/Prepare-Release.ps1 index 04f3cdc00928..25e54c35dd49 100644 --- a/eng/scripts/Prepare-Release.ps1 +++ b/eng/scripts/Prepare-Release.ps1 @@ -1,5 +1,8 @@ -param($package) - +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + $package +) function Get-LevenshteinDistance { <# @@ -71,13 +74,18 @@ function Get-LevenshteinDistance { } } +$ErrorPreference = 'Stop' $repoRoot = Resolve-Path "$PSScriptRoot/../.."; +if (!(Get-Command az)) { + throw 'You must have the Azure CLI installed: https://aka.ms/azure-cli' +} + . ${repoRoot}\eng\common\scripts\SemVer.ps1 . ${repoRoot}\eng\common\scripts\ChangeLog-Operations.ps1 $packageDirectory = Get-ChildItem "$repoRoot/sdk" -Directory -Recurse -Depth 2 -Filter $package -$serviceDirectory = ($packageDirectory).Parent.Name +$serviceDirectory = $packageDirectory.Parent.Name Write-Host "Source directory $serviceDirectory" @@ -170,11 +178,11 @@ if (!$issueId) } $fields = @{ - "Permalink usetag"="https://github.com/Azure/azure-sdk-for-net/sdk/$serviceDirectory/$package/README.md"; - "Package Registry Permalink"="https://nuget.org/packages/$package/$newVersion"; - "Library Type"=$libraryType; - "Release Type"=$releaseType; - "Version Number"=$newVersion; + "Permalink usetag"="https://github.com/Azure/azure-sdk-for-net/sdk/$serviceDirectory/$package/README.md" + "Package Registry Permalink"="https://nuget.org/packages/$package/$newVersion" + "Library Type"=$libraryType + "Release Type"=$releaseType + "Version Number"=$newVersion } Write-Host