Skip to content

Instantly share code, notes, and snippets.

@scbedd
Last active March 20, 2020 00:11
Show Gist options
  • Save scbedd/eefd6559138f68daf4641303e8e9b58a to your computer and use it in GitHub Desktop.
Save scbedd/eefd6559138f68daf4641303e8e9b58a to your computer and use it in GitHub Desktop.
Powershell Github.io Versioning v1 -> v2 Transition Script
# transition old style versioning strategy to new. inclusive of existing versions in both strategies
param (
$AzCopy,
$SASKey,
$Language,
$BlobName,
$DocLocation,
$AccountKey
)
$AccountName = ($BlobName.Replace("https://", "") -Split "\.")[0]
$DocDest = "$($BlobName)/`$web/$($Language)"
# specifically ToSemver and SortSemVersions below are shamelessly copy/pasted from an internal script written by coworker weshaggard.
# Regex inspired but simplified from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
$SEMVER_REGEX = "^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-?(?<prelabel>[a-zA-Z-]*)(?:\.?(?<prenumber>0|[1-9]\d*))?)?$"
function ToSemVer($version){
if ($version -match $SEMVER_REGEX)
{
if(-not $matches['prelabel']) {
# artifically provide these values for non-prereleases to enable easy sorting of them later than prereleases.
$prelabel = "zzz"
$prenumber = 999;
$isPre = $false;
}
else {
$prelabel = $matches["prelabel"]
$prenumber = 0
# some older packages don't have a prenumber, should handle this
if($matches["prenumber"]){
$prenumber = [int]$matches["prenumber"]
}
$isPre = $true;
}
New-Object PSObject -Property @{
Major = [int]$matches['major']
Minor = [int]$matches['minor']
Patch = [int]$matches['patch']
PrereleaseLabel = $prelabel
PrereleaseNumber = $prenumber
IsPrerelease = $isPre
RawVersion = $version
}
}
else
{
if ($ExitOnError)
{
throw "Unable to convert $version to valid semver and hard exit on error is enabled. Exiting."
}
else
{
return $null
}
}
}
function SortSemVersions($versions)
{
return $versions | Sort -Property Major, Minor, Patch, PrereleaseLabel, PrereleaseNumber -Descending
}
function Sort-Versions
{
Param (
[Parameter(Mandatory=$true)] [string[]]$VersionArray
)
# standard init and sorting existing
$versionsObject = New-Object PSObject -Property @{
OriginalVersionArray = $VersionArray
SortedVersionArray = @()
LatestGAPackage = ""
RawVersionsList = ""
LatestPreviewPackage = ""
}
if ($VersionArray.Count -eq 0)
{
return $versionsObject
}
$versionsObject.SortedVersionArray = SortSemVersions -versions ($VersionArray | % { ToSemVer $_})
$versionsObject.RawVersionsList = $versionsObject.SortedVersionArray | % { $_.RawVersion }
# handle latest and preview
# we only want to hold onto the latest preview if its NEWER than the latest GA.
# this means that the latest preview package either A) has to be the latest value in the VersionArray
# or B) set to nothing. We'll handle the set to nothing case a bit later.
$versionsObject.LatestPreviewPackage = $versionsObject.SortedVersionArray[0].RawVersion
$gaVersions = $versionsObject.SortedVersionArray | ? { !$_.IsPrerelease }
# we have a GA package
if ($gaVersions.Count -ne 0)
{
# GA is the newest non-preview package
$versionsObject.LatestGAPackage = $gaVersions[0].RawVersion
# in the case where latest preview == latestGA (because of our default selection earlier)
if ($versionsObject.LatestGAPackage -eq $versionsObject.LatestPreviewPackage)
{
# latest is newest, unset latest preview
$versionsObject.LatestPreviewPackage = ""
}
}
return $versionsObject
}
function Get-Existing-Versions
{
Param (
[Parameter(Mandatory=$true)] [String]$PkgName
)
$versionUri = "$($BlobName)/`$web/$($Language)/$($PkgName)/versioning/versions"
Write-Host "Heading to $versionUri to retrieve known versions"
try {
return ((Invoke-RestMethod -Uri $versionUri -MaximumRetryCount 3 -RetryIntervalSec 5) -Split "\n" | % {$_.Trim()} | ? { return $_ })
}
catch {
# Handle 404. If it's 404, this is the first time we've published this package.
if ($_.Exception.Response.StatusCode.value__ -eq 404){
Write-Host "Version file does not exist. This is the first time we have published this package."
}
else {
# If it's not a 404. exit. We don't know what's gone wrong.
Write-Host "Exception getting version file. Aborting"
Write-Host $_
exit(1)
}
}
}
function Update-Existing-Versions
{
Param (
[Parameter(Mandatory=$true)] [String]$PkgName,
[Parameter(Mandatory=$true)] [String[]]$ExistingVersions
)
$newStyleVersions = Get-Existing-Versions -PkgName $PkgName
Write-Host "Before I update anything, I am seeing ($newStyleVersions) new style versions"
Write-Host "And ($ExistingVersions) old style versions."
if (!$ExistingVersions)
{
$ExistingVersions = @()
$ExistingVersions += $newStyleVersions
# Write-Host "No existing versions. Adding $PkgVersion."
}
else
{
$ExistingVersions += $newStyleVersions
# Write-Host "Already Existing Versions. Adding $PkgVersion."
}
$combinedVersions = $ExistingVersions | Select-Object -Unique
Write-Host $combinedVersions
# newest first
$sortedVersionObj = (Sort-Versions -VersionArray $combinedVersions)
# write to file
$sortedVersionObj.RawVersionsList -join "`n" | Out-File -File "$($DocLocation)/versions" -Force -NoNewLine
$sortedVersionObj.LatestGAPackage | Out-File -File "$($DocLocation)/latest-ga" -Force -NoNewLine
$sortedVersionObj.LatestPreviewPackage | Out-File -File "$($DocLocation)/latest-preview" -Force -NoNewLine
& $($AzCopy) cp "$($DocLocation)/versions" "$($DocDest)/$($PkgName)/versioning/versions$($SASKey)"
& $($AzCopy) cp "$($DocLocation)/latest-preview" "$($DocDest)/$($PkgName)/versioning/latest-preview$($SASKey)"
& $($AzCopy) cp "$($DocLocation)/latest-ga" "$($DocDest)/$($PkgName)/versioning/latest-ga$($SASKey)"
}
# do a listblobs, listing everything
$LIST_EVERYTHING = "$BlobName/`$web/?restype=container&comp=list&prefix=$Language"
# find all the packages!
# this command pulls down elements that look like
# [
# "python/azure-appconfiguration/",
# "python/azure-applicationinsights/",
# "python/azure-batch/",
# "python/azure-cognitiveservices-anomalydetector/",
# "python/azure-cognitiveservices-formrecognizer/",
# ...
# ]
if (!(Test-Path "$Language.json"))
{
Write-Host "No cached listing"
az storage blob list --account-name $AccountName `
--account-key $AccountKey --container-name "`$web" `
--prefix "$Language/" --timeout 60 --num-results * `
--delimiter '/' --query '[].name | [?ends_with(@, `/`)]' `
| Out-File "$Language.json"
}
# write it to a json, get ready to partay!
$data = Get-Content "$Language.json" | ConvertFrom-Json
# at this point we have stuff of the form <language>/<packagename>/<other directory levels we don't care bout>
# this means that the first element of a split will ALWAYS be the package name
$pkgs = $data | % { ($_ -split "/")[1] } | Select-Object -Unique
# for each package name
foreach ($pkgName in $pkgs)
{
$existingVersions = (az storage blob list --account-name $AccountName `
--account-key $AccountKey --container-name "`$web" `
--prefix "$Language/$pkgName/versions" --timeout 60 --num-results * `
--query '[].name' `
| ConvertFrom-Json `
| % { $_.Replace("$Language/$pkgName/versions/", "").Trim() } )
Write-Host "For $pkgName I see the following old-style versions"
Write-Host $existingVersions
# Update-Existing-Versions -ExistingVersions $existingVersions -PkgName $pkgName
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment