tools/scripts/build.ps1 (158 lines of code) (raw):

<# .SYNOPSIS Builds csproj files with container support into docker images. Linux docker images will be Alpine which we are officially supporting due to their attack surface. This is compared to the default images when publishing, which are debian. .PARAMETER ContainerRegistry The name of the container registry to push to (optional) .PARAMETER Os Operating system to build for. Defaults to Linux .PARAMETER Arch Architecture to build. Defaults to x64 .PARAMETER ImageTag Tag to publish under. Defaults "latest" .PARAMETER PackageSource Source to use for restore - either source or nuget.config .PARAMETER BranchName The branch to use for the repo inside the registry. .PARAMETER NoBuild Whether to not build before publishing. .PARAMETER NoPublish Whether to not publish but build. .PARAMETER Debug Whether to build Release or Debug - default to Release. .PARAMETER TarFileOutput Create tar.gz file instead of container #> Param( [string] $ContainerRegistry = $null, [string] $BranchName, [string] $Os = "linux", [string] $Arch = "x64", [string] $ImageTag = "latest", [switch] $NoBuild, [string] $PackageSource = $null, [switch] $NoPublish, [switch] $Debug, [string] $TarFileOutput ) $ErrorActionPreference = "Stop" $Path = & (Join-Path $PSScriptRoot "get-root.ps1") -fileName "Industrial-IoT.sln" $configuration = "Release" if ($script:Debug.IsPresent) { $configuration = "Debug" } $imageNamespace = $null if (![string]::IsNullOrWhiteSpace($script:ContainerRegistry)) { $imageNamespace = "public" if ($script:ContainerRegistry -eq "industrialiotdev") { if (![string]::IsNullOrWhiteSpace($script:BranchName)) { # Set namespace name based on branch name $namespace = $script:BranchName if ($namespace.StartsWith("feature/")) { # dev feature builds $namespace = $namespace.Replace("feature/", "") } $namespace = $namespace.Replace("_", "/") $imageNamespace = $namespace.Substring(0, [Math]::Min($namespace.Length, 24)) } } } $env:DOTNET_CONTAINER_REGISTRY_CHUNKED_UPLOAD = $true $env:DOTNET_CONTAINER_REGISTRY_CHUNKED_UPLOAD_SIZE_BYTES = 131072 $env:DOTNET_CONTAINER_REGISTRY_PARALLEL_UPLOAD = $false # legacy variables for dotnet SDK version < 8.0.400 $env:SDK_CONTAINER_REGISTRY_CHUNKED_UPLOAD = $true $env:SDK_CONTAINER_REGISTRY_CHUNKED_UPLOAD_SIZE_BYTES = 131072 $env:SDK_CONTAINER_REGISTRY_PARALLEL_UPLOAD = $false # Find all container projects, publish them and then push to container registry Get-ChildItem $Path -Filter *.csproj -Recurse | ForEach-Object { $projFile = $_ $properties = ([xml] (Get-Content -Path $projFile.FullName)).Project.PropertyGroup ` | Where-Object { ![string]::IsNullOrWhiteSpace($_.ContainerRepository) } ` | Select-Object -First 1 if ($properties) { $runtimeId = "$($script:Os)-$($script:Arch)" if ($script:Arch -eq "arm") { # Because of alpine $runtimeId = "$($script:Os)-musl-$($script:Arch)" } if (!$script:NoBuild.IsPresent) { Write-Host "Build $($projFile.FullName) ..." dotnet clean $projFile.FullName -c $configuration ` -r $runtimeId | Out-Null if (![string]::IsNullOrWhiteSpace($script:PackageSource)) { if (-not (Test-Path $script:PackageSource)) { Write-Host "Restore from source $($script:PackageSource)..." dotnet restore $projFile.FullName -r $runtimeId ` --source $script:PackageSource } else { Write-Host "Restore using $($script:PackageSource) file..." dotnet restore $projFile.FullName -r $runtimeId ` --configfile $script:PackageSource } Write-Host "Building..." dotnet build $projFile.FullName -c $configuration --no-restore ` -r $runtimeId /p:TargetLatestRuntimePatch=true } else { Write-Host "Building with default package source..." dotnet build $projFile.FullName -c $configuration ` -r $runtimeId /p:TargetLatestRuntimePatch=true } if ($LastExitCode -ne 0) { throw "Failed to build container." } } if ($script:NoPublish.IsPresent) { return } $fullName = "" $extra = @() if ($imageNamespace) { $fullName = "$($fullName)$($imageNamespace)/" } $fullName = "$($fullName)$($properties.ContainerRepository)" $fullTag = "$($script:ImageTag)-$($script:Os)-$($script:Arch)" if ($script:Debug.IsPresent) { $fullTag = "$($fullTag)-debug" } Write-Host "Publish $($projFile.FullName) as $($fullName):$($fullTag)..." $baseImage = $($properties.ContainerBaseImage -split "-")[0] # see architecture tags e.g., here https://hub.docker.com/_/microsoft-dotnet-aspnet if ($script:Arch -eq "x64") { $baseImage = "$($baseImage)-azurelinux3.0-amd64" } if ($script:Arch -eq "arm64") { $baseImage = "$($baseImage)-azurelinux3.0-arm64v8" } if ($script:Arch -eq "arm") { $baseImage = "$($baseImage)-alpine-arm32v7" } if (![string]::IsNullOrWhiteSpace($script:TarFileOutput)) { Write-Host "Publish as tarball to $($script:TarFileOutput)/$($fullName).tar.gz..." $extra += "/p:ContainerArchiveOutputPath=$($script:TarFileOutput)" } elseif ($script:ContainerRegistry) { Write-Host "Publish to container registry $($script:ContainerRegistry)..." $extra += "/p:ContainerRegistry=$($script:ContainerRegistry)" } dotnet publish $projFile.FullName -c $configuration --self-contained false --no-build ` -r $runtimeId /p:TargetLatestRuntimePatch=true ` /p:RuntimeIdentifiers=$runtimeId ` /p:ContainerBaseImage=$baseImage ` /p:ContainerRepository=$($fullName) ` /p:ContainerImageTag=$($fullTag) ` $extra /t:PublishContainer if ($LastExitCode -ne 0) { throw "Failed to publish container." } Write-Host "$($fullName):$($fullTag) published." } } # The tar.gz was published as $($fullName)-$runtimeId.tar.gz, let's rename them Get-ChildItem -Filter "*.tar.gz" -Path $script:TarFileOutput -Recurse ` | Rename-Item -NewName {$_.Name -replace "-$($runtimeId)", "" }