Noveris.Build.psm1

<#
#>


################
# Global settings
$InformationPreference = "Continue"
$ErrorActionPreference = "Stop"

################
# Script variables
$semVerPattern = "^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"

$script:BuildState = [PSCustomObject]@{
    Stages = @{}
    RunState = @{}
}

Function Use-BuildVar
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [AllowEmptyString()]
        [AllowNull()]
        [string]$Source,

        [Parameter(mandatory=$true)]
        [ValidateNotNull()]
        [ScriptBlock]$Check
    )

    process
    {
        $ret = $Source | ForEach-Object -Process $Check
        if (!$ret)
        {
            Write-Error "Source string (${Source}) failed validation"
            return
        }

        $Source
    }
}

<#
#>

Function Set-BuildVersionInfo
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNull()]
        [AllowEmptyString()]
        [string[]]$Sources
    )

    process
    {
        foreach ($src in $Sources)
        {
            if ($src -eq $null -or $src -eq "")
            {
                continue
            }

            Write-Verbose "Processing version candidate: ${src}"

            # Strip any refs/tags/ reference at the beginning of the version source
            $tagBranch = "refs/tags/"
            if ($src.StartsWith($tagBranch))
            {
                Write-Verbose "Version starts with refs/tags format - Removing"
                $src = $src.Substring($tagBranch.Length)
            }

            if ($src.StartsWith("v"))
            {
                Write-Verbose "Version starts with 'v' - Removing"
                $src = $src.Substring(1)
            }

            if ($src -notmatch $semVerPattern)
            {
                Write-Verbose "Version string not in correct format. skipping"
                continue
            }
          
            $Prerelease = $Matches[4]
            if ($Prerelease -eq $null) {
                $Prerelease = ""
            }
        
            $Buildmetadata = $Matches[5]
            if ($Buildmetadata -eq $null) {
                $Buildmetadata = ""
            }
        
            Write-Verbose "Version is valid"
            $script:BuildState.RunState["Version"] = [ordered]@{
                Full = $src
                Major = [Convert]::ToInt32($Matches[1])
                Minor = [Convert]::ToInt32($Matches[2])
                Patch = [Convert]::ToInt32($Matches[3])
                Prerelease = $Prerelease
                Buildmetadata = $Buildmetadata
            }

            return
        }

        # throw error as we didn't find a valid version source
        Write-Error "Could not find a valid version source"
    }
}

<#
#>

Function Set-BuildStage
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Stage,

        [Parameter(mandatory=$true)]
        [ValidateNotNull()]
        [ScriptBlock]$Script
    )

    process
    {
        $script:BuildState.Stages[$Stage] = $Script
    }
}

<#
#>

Function Remove-BuildStage
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Stage
    )

    process
    {
        $script:BuildState.Stages.Remove($Stage)
    }
}

<#
#>

function Invoke-BuildStages
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNull()]
        [string[]]$Stages
    )

    process
    {
        $Stages | ForEach-Object {
            if (!$script:BuildState.Stages.ContainsKey($_) -or $script:BuildState.Stages[$_] -eq $null)
            {
                Write-Error "Processing for stage ($_) requested, but it does not exist or is null."
                return
            }

            Write-Information ""
            Write-Information ("================ {0} Stage($_) BEGIN" -f [DateTime]::Now.ToString("yyyyMMdd HHmm"))
            $script:BuildState.RunState | ForEach-Object -Process $script:BuildState.Stages[$_]
            Write-Information ("================ {0} Stage($_) END" -f [DateTime]::Now.ToString("yyyyMMdd HHmm"))
        }
    }
}

<#
#>

Function Format-TemplateFile
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Template,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Target,

        [Parameter(Mandatory=$true)]
        [Hashtable]$Content
    )

    process
    {
        Get-Content $Template -Encoding UTF8 | Format-TemplateString -Content $Content | Out-File -Encoding UTF8 $Target
    }
}

<#
#>

Function Format-TemplateString
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,ValueFromPipeline)]
        [AllowEmptyString()]
        [string]$TemplateString,

        [Parameter(Mandatory=$true)]
        [Hashtable]$Content
    )

    process
    {
        $working = $TemplateString

        foreach ($key in $Content.Keys)
        {
            $working = $working.Replace($key, $Content[$key])
        }

        $working
    }
}

<#
#>

Function Publish-ArtifactFile
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Uri,

        [Parameter(mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [string]$Method = "Put",

        [Parameter(mandatory=$false)]
        [ValidateNotNull()]
        [HashTable]$Headers = @{},

        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$File,

        [Parameter(mandatory=$false)]
        [ValidateNotNull()]
        [PSCredential]$Credential
    )

    process
    {
        $args = @{
            Method = $Method
            Uri = $Uri
            Headers = $Headers
            InFile = $File
            UseBasicParsing = $true
            #PreserveAuthorizationOnRedirect = $true
        }

        if ($PSBoundParameters.Keys -contains "Credential")
        {
            #$args["Authentication"] = "Basic"
            $args["Credential"] = $Credential
        }

        $response = Invoke-RestMethod @args
    }
}

<#
#>

Function Get-BuildNumber {
    [CmdletBinding()]
    param(
    )
  
    process
    {
        $MinDate = New-Object DateTime -ArgumentList 1970, 1, 1
        [Int64]([DateTime]::Now - $MinDate).TotalDays
    }
}

<#
#>

Function Invoke-BuildProcess
{
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$FilePath,

        [Parameter(mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [string[]]$Arguments
    )

    process
    {
        $args = @{
            FilePath = $FilePath
            NoNewWindow = $true
            PassThru = $true
            Wait = $true
        }

        if ($PSBoundParameters.Keys -contains "Arguments")
        {
            $args["ArgumentList"] = $Arguments
        }

        Write-Information ([string]::Format("Execute Process: {0}", $FilePath))
        Write-Information ([string]::Format("Arguments: {0}", ($Arguments -join " ")))
        $Process = Start-Process @args

        Write-Information ([string]::Format("Process Exit Code: {0}", $Process.ExitCode))
        if ($Process.ExitCode -ne 0)
        {
            Write-Error ([string]::Format("Call to {0} returned non-zero ({1})", $FilePath, $Process.ExitCode))
        }
    }
}