Publish-Application.psm1

#
function Get-Absolute-Path([string]$path){
    if($path.StartsWith(".")){
        $path = [IO.Path]::Combine((Get-Location).Path,$path)
    }
    return [IO.Path]::GetFullPath($path)
}
#
function Get-Default-Settings($debug,$configuration,[string] $publishPath,[string] $project){
    #
    $setting = @{}
    #
    $setting.Enabled =  $true
    if($null -ne $configuration.Enabled){
        $setting.Enabled = $configuration.Enabled
    } 
    #
    $setting.Configuration =  "Release"
    if($debug){
        if($null -ne  $configuration.Configuration){
            $setting.Configuration = $configuration.Configuration
        }
    }
    #
    $setting.Runtime =  "linux-x64"
    if($null -ne  $configuration.Runtime){
        $setting.Runtime =$configuration.Runtime 
    } 
    #
    $setting.SelfContained =  $false
    if($null -ne  $configuration.SelfContained){
        $setting.SelfContained = $configuration.SelfContained
    }
    #
    $setting.SingleFile =  $false
    if($null -ne  $configuration.SingleFile ){
        $setting.SingleFile = $configuration.SingleFile
    }
    #
    $path = $configuration.Path
    if([string]::IsNullOrEmpty($path)){
        $path = ""
    }
    #
    if([string]::IsNullOrEmpty($path) -and $null -ne $project){
        $path = [IO.Path]::GetFileNameWithoutExtension($project)
    }
    #
    $setting.Path = [IO.Path]::Combine($publishPath,  $path);
    return $setting
}
<#
.Synopsis
   Automatic Publish Tool (APT)
.DESCRIPTION
   Publish visual studio solution
.EXAMPLE
   Publish-Application D:\Projects\project.sln D:\Project\publish\admin
.NOTES
   Author: Imrich Szolik
#>

function Publish-Application
{
    [CmdletBinding()]
    [Alias()]
    Param(
        # Solution file (sln)
        [string]
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$false, HelpMessage="Project file.")]
        $Solution,

        #Publish path.
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$false, HelpMessage="Publish path.")]
        [string]
        $PublishPath,

        #config
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$false, HelpMessage="Publish json config")]
        [string]
        $JsonConfig = "(lomtec|nuaktiv)\.json",
        
        #verbosity
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$false, HelpMessage="Build verbosity")]
        [ValidateSet('quiet','minimal','normal','detailed', 'diagnostic')]
        [string]
        $Verbosity = "quiet",    
        
        #verbosity
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$false, HelpMessage="Build platform")]
        [ValidateSet('all','linux','windows')]
        [string]
        $Platform = "all",
        
        #enable debug mode
        [switch]
        [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$false, HelpMessage="Enable Debug compilation")]
        $EnableDebug
    )
    Begin{
        #required
        if ($null -eq (Get-Command dotnet -ErrorAction SilentlyContinue)) { throw "Please install dotnet SDK. [ Download https://dotnet.microsoft.com/en-us/download ]" }
        if ($null -eq (Get-Command nuget  -ErrorAction SilentlyContinue)) { throw "Please install nuget CLI. [ Download https://www.nuget.org/downloads & add copy nuget.exe to %userprofile%\.dotnet\tools ]" }
        #validation
        if ($platform -eq 'linux') {
            $msbuild = $null
        }    
        else{
            $msbuild = (Get-MsBuildCommand -ErrorAction SilentlyContinue)
            if( $null -eq $msbuild) { throw "Please install Visual Studio. [ Download https://visualstudio.microsoft.com/downloads/ ]" }
        }
        #solution
        if( (-not (Test-Path -Path $Solution -PathType Leaf)) -or (-not ( $Solution -like '*.sln')) ){ throw "$Solution is not valid" }

        $solution = ( Resolve-Path $Solution ).Path
        $solutionPath = Split-Path -Parent $Solution
        #
        $PublishPath = Get-Absolute-Path $PublishPath
        #
    }
    Process{
        #restore packages
        Write-Host "#### APT NUGET restoring packages ####"
        nuget restore $solution -verbosity quiet
        if($LastExitCode) { throw "NUGET RESTORE failed" }
        
        #config
        $lomtecConfigs =  Get-ChildItem -Recurse $solutionPath | Where-Object { $_.Name -Match $JsonConfig } | Select-Object -ExpandProperty FullName
        if($lomtecConfigs.Length -eq 0){ throw "Not found any build configuration [$JsonConfig]!"}
        #
        foreach($lomtec in $lomtecConfigs){
            #has project section
            $project = Get-ChildItem (Split-Path -Parent $lomtec) -Filter "*.csproj" | Select-Object -ExpandProperty FullName -First 1
            if($null -eq $project){
                Write-Verbose "Missing csproj file for [$lomtec]"
                Continue
            }
            #project path
            $projectPath = Split-Path $project -Parent
            
            #json
            $json = Get-Content $lomtec | ConvertFrom-Json

            #has build section
            if($null -eq $json.Build){
                Write-Warning "Missing Build section for [$lomtecConfigs]"
                Continue
            }

            #process Publish or Nuget
            if($null -ne $json.Build.Publish -and $json.Build.Publish.Count -gt 0){
                #
                foreach($config in $json.Build.Publish){
                    #setting
                    $setting = Get-Default-Settings $EnableDebug.IsPresent $config $PublishPath $project

                    #detailed log
                    Write-Verbose " Configuration $($setting | ConvertTo-Json -Compress)"
                    
                    #platform validation
                    if($platform -ne 'all'){
                        #
                        if($platform -eq 'linux'){
                            if($setting.Runtime -notlike "linux*") {
                                Continue
                            }
                        }
                        #
                        else{
                            if($setting.Runtime -notlike "win*") {
                                Continue
                            }
                        }
                    }
                    #
                    if( (($json.Build.Publish.Length -eq 0) -and ($json.Build.Publish.Enabled -eq $false)) -or ($setting.Enabled -eq $false) ) {
                        Write-Warning "#### APT PUBLISH $(Split-Path -Leaf $project) [$(Split-Path -Leaf $setting.Path)] is not enabled ####"
                    }
                    else{                    
                        #initial cleanup for nuget
                        Get-ChildItem $projectPath -Recurse -Directory -Filter obj | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                        Get-ChildItem $projectPath -Recurse -Directory -Filter bin | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                        #
                        if(($json.Build.Command -eq 'msbuild') -and ($null -ne $msbuild)){
                            Write-Host "#### APT PUBLISH $(Split-Path -Leaf $project) to $($setting.Path) [msbuild] ####"
                            & "$msbuild" -nologo -verbosity:$Verbosity -property:Configuration=$($setting.Configuration) /property:OutDir=$($setting.Path) -restore $project 
                            if($LastExitCode) {    throw "MSBUILD BUILD $(Split-Path -Leaf $project) failed" }
                        }
                        else{
                            Write-Host "#### APT PUBLISH $(Split-Path -Leaf $project) to $($setting.Path) [dotnet] ####"
                            dotnet publish -nologo --verbosity $Verbosity --runtime $setting.Runtime --configuration $setting.Configuration --self-contained $setting.SelfContained -p:PublishSingleFile=$($setting.SingleFile) $project --output $setting.Path
                            if($LastExitCode) { throw "DOTNET PUBLISH $(Split-Path -Leaf $project) failed" }
                        }
                        #final cleanup for nuget
                        Get-ChildItem $projectPath -Recurse -Directory -Filter obj | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                        Get-ChildItem $projectPath -Recurse -Directory -Filter bin | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue                        
                    }
                }
            }
            elseif($null -ne $json.Build.Nuget){
                #setting
                $setting = Get-Default-Settings $EnableDebug.IsPresent $json.Build.Nuget $PublishPath 

                #detailed log
                Write-Verbose "Configuration $($setting | ConvertTo-Json -Compress)"

                #
                if( ($json.Build.Nuget.Enabled -eq $false) -or ($setting.Enabled -eq $false) ){
                    Write-Warning "Build/Nuget is disabled for $(Split-Path -Leaf $project)"
                }
                else{
                    #initial cleanup for nuget
                    Get-ChildItem $projectPath -Recurse -Directory -Filter obj | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                    Get-ChildItem $projectPath -Recurse -Directory -Filter bin | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                    
                    if(($json.Build.Command -eq 'msbuild') -and ($null -ne $msbuild)){
                        Write-Host "#### APT BUILD $(Split-Path -Leaf $project) [msbuild] ####"
                        & "$msbuild" -nologo -verbosity:$Verbosity -property:Configuration=$($setting.Configuration) -restore $project 
                        if($LastExitCode) {    throw "MSBUILD BUILD $(Split-Path -Leaf $project) failed" }
                    }
                    else{
                        Write-Host "#### APT BUILD $(Split-Path -Leaf $project) [dotnet] ####"
                        dotnet build -nologo --verbosity $Verbosity --configuration $setting.Configuration --no-incremental $project 
                        if($LastExitCode) {    throw "DOTNET BUILD $(Split-Path -Leaf $project) failed" }
                    }

                    Write-Host "#### APT NUGET $(Split-Path -Leaf $project) to $($setting.Path) ####"
                    $nuspec = $project.Replace("csproj","nuspec")
                    if(Test-Path -Path $nuspec -PathType Leaf){
                        nuget pack -OutputDirectory $setting.Path -properties Configuration=$($setting.Configuration) -verbosity quiet $nuspec
                        if($LastExitCode) { throw "NUGET PACK $(Split-Path -Leaf $project) failed" }
                    }
                    else{
                        Write-Warning "Missing nuspec $nuspec!"
                    }
                    #final cleanup for nuget
                    Get-ChildItem $projectPath -Recurse -Directory -Filter obj | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                    Get-ChildItem $projectPath -Recurse -Directory -Filter bin | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
                }
            }
            else{
                Write-Warning "Missing Build/Publish or Build/Nuget section for [$lomtecConfigs]!"
            }
        }
        #cleanup
        Write-Verbose "Publish cleanup [$PublishPath]"
        Get-ChildItem -Path $PublishPath -Recurse -Filter *.pdb -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
        Get-ChildItem -Path $PublishPath -Recurse -Filter $JsonConfig -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
        Get-ChildItem -Path $PublishPath -Recurse -Filter appsettings.*.json -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
        Get-ChildItem -Path $PublishPath -Recurse -Filter web.*.config -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue
    }
    End{
    }
}
Export-ModuleMember -Function Publish-Application
# SIG # Begin signature block
# MIIIEwYJKoZIhvcNAQcCoIIIBDCCCAACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCOnNoivgxFYt6k
# WUwuLVwQkUy51NFQkOmB5gQHDXbYD6CCBQ8wggULMIIC86ADAgECAgIApTANBgkq
# hkiG9w0BAQsFADCBoDELMAkGA1UEBhMCU0sxETAPBgNVBAgTCFNsb3Zha2lhMRMw
# EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpMb210ZWMuY29tMSswKQYDVQQD
# EyJMb210ZWMuY29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MScwJQYJKoZIhvcN
# AQkBFhhJbXJpY2guU3pvbGlrQGxvbXRlYy5jb20wHhcNMTkwMzI2MTUwNDQzWhcN
# MzAwMTAxMDAwMDAwWjCBkzELMAkGA1UEBhMCU0sxETAPBgNVBAgTCFNsb3Zha2lh
# MRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpMb210ZWMuY29tMR4wHAYD
# VQQDExVMb210ZWMuY29tIFBvd2Vyc2hlbGwxJzAlBgkqhkiG9w0BCQEWGEltcmlj
# aC5Tem9saWtAbG9tdGVjLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
# ggEBAL4n4nCHbkdrf09IHNFQ2P/z6I43GKScsFJOQHUMkRD3ALoUFL/URC9sW2fY
# rqG5VkFAKhnM0VxeiICR53cAshNShjFf58PhaS973jtCoJcaugIVBVoFIuQ+gnNY
# Jp2VdBbIPKMW4JjjZOxBEkHpMWmfitXKWGKeU68Qcn3oI6PO+YSztfXLe1NU+1GI
# O3fA7E0vHVPUf/qWZXMYU5ElLQVm9AXbfX79mTgl76A57+OC6j+Aehkd2OPfUl4w
# snox3fOyUAUA8iojeWh97PpXd/s+RkuxWdgsC4YSWDUjhZSzBkml9uerYqo9a+XA
# b39dvkpK9TPl3q5HNBQMkCfp8bkCAwEAAaNaMFgwCQYDVR0TBAIwADALBgNVHQ8E
# BAMCB4AwKwYDVR0lBCQwIgYIKwYBBQUHAwMGCisGAQQBgjcCARUGCisGAQQBgjcC
# ARYwEQYJYIZIAYb4QgEBBAQDAgSwMA0GCSqGSIb3DQEBCwUAA4ICAQAJJapv9skY
# jh5HTsJnqDdtqh7YOOXuA8g+DKBj+5gDEZE5V9VhAFVp8UJ9RoITGGIRTVId0lqc
# LJiVSTHx305VW9aID8vo77kfrTyXvPXNIsTtHnPkkwH47+CoiY3IpPQLjUA/Q6Qd
# qwINvvwom7/Wc+OoIqlPdJH5DbBrIy85dr6M/Lm3Rw2BolcTRwXTB3xAhweth78B
# P6pbcAd32FdymkRopLIihuNs7g7ZR/Q/5803G+OiQIMRGyTvaQ+aQjJgFpkzp7NI
# whzougfCOV47Sc89jEpUqw16i2UFfz2ywOlWUyYtue1S1PjM1ljgJfRo+e0wUnFp
# gFQzXGF1bTYVaQ4e3nJleADfvqeXoH2AYeBTbz9BcogkkfURAC3iiob1bNs5jE1C
# brEDCw6m/03k0oOmm3xQksXyAhBYuUkRwu9jd4y3FwZ/syDGLz3b6cY8o1YyINOO
# A3B2r92shNt0rWhJu3v+qcIVmFQ0aKlhNNRoiVlQgJ7NgO0UV+vU2lgiscpUSxEt
# xKN+450r49su06NA6zsyn3CELUmVkPyjx5fyizwt9KxVuYOUSEb32Y7QCffHJ1qt
# F6SuQrKbgb/24y7cCDW6PDVRvPOySUlKu9sPykICDjvzXBvjYEILM7AmtYCIBGQg
# imBsQvTEoXJXiwAOi1XNz3LxcjQHQ/ZM4zGCAlowggJWAgEBMIGnMIGgMQswCQYD
# VQQGEwJTSzERMA8GA1UECBMIU2xvdmFraWExEzARBgNVBAcTCkJyYXRpc2xhdmEx
# EzARBgNVBAoTCkxvbXRlYy5jb20xKzApBgNVBAMTIkxvbXRlYy5jb20gQ2VydGlm
# aWNhdGlvbiBBdXRob3JpdHkxJzAlBgkqhkiG9w0BCQEWGEltcmljaC5Tem9saWtA
# bG9tdGVjLmNvbQICAKUwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEK
# MAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3
# AgELMQ4wDAYKKwYBBAGCNwIBFjAvBgkqhkiG9w0BCQQxIgQgIJzxELEUryMZyFOM
# +t+DF6Gq6VFG9hj7Y4FeN1Uv9P4wDQYJKoZIhvcNAQEBBQAEggEAeI0fqy0utv0F
# wbpo0ZWTHsHw2ZI2uwfnDmfD096ndCb89FdZ0rKH8MqM6fvxVg9c0RiHX8UjEdRt
# 8EQxlqRn2pVJ46MaMbXbAkiK6jnZjgz1fBFufneFRsQrkzDcQSXizimCUdxW595Q
# 2lrtp53Mbm9ZeUIlJAE+IV7pK+92QwZ2umMiAUSfZSszv10cbDvwnQnubJ4sFuyT
# 9nEb8NqtC2mBJdHi9pcESP+b/d3UiGKm72s+jgXWlceHcTSnKjkLltO5pnMuI6f6
# fXnNtRflbSM70H8NZalpW9aXJp+0SOfF8zTuhg8BN9FitN3VucoHpeW6tgGk0m9V
# Veev1RF8CQ==
# SIG # End signature block