diff --git a/.gitignore b/.gitignore index aa0331923..20b8ed6e5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ node_modules .deps global.json msbuild.ProjectImports.zip +.dotnet/ +.tools/ diff --git a/build/RuntimeStoreInstaller.targets b/build/RuntimeStoreInstaller.targets index eaece814e..6c23daf81 100644 --- a/build/RuntimeStoreInstaller.targets +++ b/build/RuntimeStoreInstaller.targets @@ -31,7 +31,11 @@ $(TimestampFreeRSArchivePrefix)linux-x64.patch.tar.gz - + + + + + diff --git a/scripts/UploadBlobs.ps1 b/scripts/UploadBlobs.ps1 new file mode 100644 index 000000000..be0bdab8d --- /dev/null +++ b/scripts/UploadBlobs.ps1 @@ -0,0 +1,145 @@ +<# +.SYNOPSIS +Deploys a build to an Azure blob store + +.PARAMETER AccountName +The account name for the Azure account + +.PARAMETER AccountKey +The account key for the Azure account + +.PARAMETER BuildNumber +The build number of the current build + +.PARAMETER BaseFeedUrl +The base URI of the package feed (may be different than blobBaseUrl for private-only blobs) + +.PARAMETER ContainerName +The container name. Defaults to 'dotnet' + +.PARAMETER ArtifactsPath +The path to the build outputs +#> +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [Parameter(Mandatory = $true)] + $AccountName, + [Parameter(Mandatory = $true)] + $AccountKey, + [Parameter(Mandatory = $true)] + $BuildNumber, + [Parameter(Mandatory = $true)] + $ArtifactsPath, + $BaseBlobFeedUrl, + $ContainerName = 'dotnet' +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 1 + +Import-Module -Scope Local "$PSScriptRoot/common.psm1" + +if (!(Get-Command 'az' -ErrorAction Ignore)) { + Write-Error 'Missing required command: az. Please install the Azure CLI and ensure it is available on PATH.' +} + +$repoRoot = Resolve-Path "$PSScriptRoot/.." + +$sleetVersion = '2.3.25' +$sleet = "$repoRoot/.tools/sleet.$sleetVersion/tools/sleet.exe" + +if (-not (Test-Path $sleet)) { + mkdir "$repoRoot/.tools/sleet.$sleetVersion" -ErrorAction Ignore | Out-Null + $installScriptPath = "$repoRoot/.dotnet/dotnet-install.ps1" + Invoke-WebRequest -UseBasicParsing -OutFile "$repoRoot/.tools/sleet.$sleetVersion.zip" https://www.nuget.org/api/v2/package/Sleet/$sleetVersion + Expand-Archive "$repoRoot/.tools/sleet.$sleetVersion.zip" -DestinationPath "$repoRoot/.tools/sleet.$sleetVersion" +} + +[xml] $versionProps = Get-Content "$repoRoot/version.props" +$props = $versionProps.Project.PropertyGroup +$VersionPrefix = "$($props.AspNetCoreMajorVersion).$($props.AspNetCoreMinorVersion).$($props.AspNetCorePatchVersion)" + +$blobFolder = "$ContainerName/aspnetcore/store/$VersionPrefix-$BuildNumber" +$packagesFolder = "$blobFolder/packages/" + +$blobBaseUrl = "https://$AccountName.blob.core.windows.net/$blobFolder" +$packageBlobUrl = "https://$AccountName.blob.core.windows.net/$packagesFolder" + +if (-not $BaseBlobFeedUrl) { + $BaseBlobFeedUrl = "https://$AccountName.blob.core.windows.net/$packagesFolder" +} +else { + $BaseBlobFeedUrl = "$BaseBlobFeedUrl/$packagesFolder" +} + +$packageGlobPath = "$ArtifactsPath/packages/**/*.nupkg" +$globs = ( + @{ + basePath = "$ArtifactsPath/lzma" + pattern = "*" + destination = $blobFolder + }, + @{ + basePath = "$ArtifactsPath/installers" + pattern = "*" + destination = $blobFolder + }) + +$sleetConfigObj = @{ + sources = @( + @{ + name = "feed" + type = "azure" + path = $packageBlobUrl + baseURI = $BaseBlobFeedUrl + container = $ContainerName + connectionString = "DefaultEndpointsProtocol=https;AccountName=$AccountName;AccountKey=$AccountKey" + }) +} + +$sleetConfig = "$repoRoot/.tools/sleet.json" +$sleetConfigObj | ConvertTo-Json | Set-Content -Path $sleetConfig -Encoding Ascii +if ($PSCmdlet.ShouldProcess("Initialize remote feed in $packageBlobUrl")) { + Invoke-Block { & $sleet init --config $sleetConfig --verbose } +} + +Get-ChildItem -Recurse $packageGlobPath ` + | split-path -parent ` + | select -Unique ` + | % { + if ($PSCmdlet.ShouldProcess("Push packages in $_ to $packageBlobUrl")) { + Invoke-Block { & $sleet push --verbose --config $sleetConfig --source feed --force $_ } + } +} + +[string[]] $otherArgs = @() + +if ($VerbosePreference) { + $otherArgs += '--verbose' +} + +if ($WhatIfPreference) { + $otherArgs += '--dryrun' +} + +$globs | ForEach-Object { + $pattern = $_.pattern + $basePath = $_.basePath + $destination = $_.destination + if (!(Get-ChildItem -Recurse "$basePath/$pattern" -ErrorAction Ignore)) { + Write-Warning "Expected files in $basePath/$pattern but found none" + } + + Invoke-Block { & az storage blob upload-batch ` + --account-name $AccountName ` + --account-key $AccountKey ` + --verbose ` + --pattern $pattern ` + --destination $destination.TrimEnd('/') ` + --source $basePath ` + --no-progress ` + @otherArgs + } +} + +Write-Host -f green "Done!" diff --git a/scripts/common.psm1 b/scripts/common.psm1 index b621d4819..a6f8e19e4 100644 --- a/scripts/common.psm1 +++ b/scripts/common.psm1 @@ -15,7 +15,10 @@ function Invoke-Block([scriptblock]$cmd) { # - $?: did the powershell script block throw an error # - $lastexitcode: did a windows command executed by the script block end in error if ((-not $?) -or ($lastexitcode -ne 0)) { - Write-Warning $error[0] + if ($error -ne $null) + { + Write-Warning $error[0] + } throw "Command failed to execute: $cmd" } }