Scripts/Deploy.ps1


function CmxGetRelevantTestFolders($copySource)
{
    <#
    .SYNOPSIS
    Gets an array of all test folders which should be copied.
    #>

    $path =  "$copySource\Tests\*"
    $filters = @("_CRT", "_Framework", "_Settings", "Base.*", "Basics.*", "CommonServices.*", "Engineering.*", "FAL.*", "Hwcn.Basics.*", "S7F*", "Safety.*", "SysInt*", "Test.Execution.Butler*", "TifLib*")
    $allItems = @()
    foreach($filter in $filters)
    {
        [array]$items = Get-ChildItem -Path $path -Filter $filter
        foreach($item in $items)
        {
            $fp = $item.FullName
            $allItems += $fp
        }
    }
    return $allItems
}

function CmxDownloadBuild([string]$buildFolder, [string]$copyTarget)
{
    <#
    .SYNOPSIS
    Copies a S7F build from the given build folder into the given target folder.
    #>


    $date1 = (Get-Date)
    $copySource = "$buildFolder\Release\x64"
    $sourceBin = "$copySource\Bin"
    $sourceData = "$copySource\Data"
    $sourceTests =  "$copySource\Tests"

    <#
    Robocopy arguments:
 
    MIR
    Mirror the folder recursively from source to target. In target remove all files and folders
    that no longer exist in source.
     
    MT:n
    Copy multithreaded. Launch n threads. Default is 8.
 
    R:n
    Number of retries on a failed copy. Default is 1 million.
     
    W:n
    Wait time between retries - default is 30 seconds.
     
    NP
    No Progress is displayed.
     
    NS
    No file sizes are displayed.
     
    NC
    No file classes are displayed.
     
    NFL
    No file names are displayed.
     
    NDL
    No directory names are displayed.
     
    COPY:flags
    Copies attributes if specified.
    D=Data and Timestamps, A=Attributes, T=Timestamps, S=Security=NTFS ACLs, O=Owner info, U=aUditing info
 
    XD dirs
    Exclude directories matching the given paths.
    #>


    $copyArgs = "/MIR /MT:8 /R:10 /W:10 /NP /NS /NC /NFL /NDL /COPY:D"

    $frameLogFile = CreateLogFilePath("Frame")
    $binLogFile = CreateLogFilePath("Bin")
    $dataLogFile = CreateLogFilePath("Data")
    # $testsLogFile = CreateLogFilePath("Tests")
    
    $frameArgs = "`"$copySource`" `"$copyTarget`" $copyArgs /XD `"$sourceBin`" `"$sourceData`" `"$sourceTests`" /LOG:`"$frameLogFile`" "
    $binArgs = "`"$copySource\Bin`" `"$copyTarget\Bin`" $copyArgs /LOG:`"$binLogFile`" "
    $dataArgs = "`"$copySource\Data`" `"$copyTarget\Data`" $copyArgs /LOG:`"$dataLogFile`" "
    # $testsArgs = "`"$copySource\Tests`" `"$copyTarget\Tests`" $copyArgs /LOG:`"$testsLogFile`" "

    $testsArgs1 = "`"$copySource\Tests\Safety.Base.Test`" `"$copyTarget\Tests\Safety.Base.Test`" $copyArgs "
    $testsArgs2 = "`"$copySource\Tests\FileStorage.Test`" `"$copyTarget\Tests\FileStorage.Test`" $copyArgs "
    $testsArgs3 = "`"$copySource\Tests\_Framework`" `"$copyTarget\Tests\_Framework`" $copyArgs "
    $testsArgs4 = "`"$copySource\Tests\SysInt`" `"$copyTarget\Tests\SysInt`" $copyArgs "
    $testsArgsRest = "`"$copySource\Tests`" `"$copyTarget\Tests`" $copyArgs /XD `"$copySource\Tests\Safety.Base.Test`" `"$copySource\Tests\FileStorage.Test`" `"$copySource\Tests\_Framework`" `"$copySource\Tests\SysInt`" "


    $frameProcess = StartDownloadProcess($frameArgs)
    $binProcess = StartDownloadProcess($binArgs)
    $dataProcess = StartDownloadProcess($dataArgs)
    # $testsProcess = StartDownloadProcess($testsArgs)
    $testsProcess1 = StartDownloadProcess($testsArgs1)
    $testsProcess2 = StartDownloadProcess($testsArgs2)
    $testsProcess3 = StartDownloadProcess($testsArgs3)
    $testsProcess4 = StartDownloadProcess($testsArgs4)
    $testsProcessRest = StartDownloadProcess($testsArgsRest)

    $frameProcess.WaitForExit()
    $binProcess.WaitForExit()
    $dataProcess.WaitForExit()
    # $testsProcess.WaitForExit()
    $testsProcess1.WaitForExit()
    $testsProcess2.WaitForExit()
    $testsProcess3.WaitForExit()
    $testsProcess4.WaitForExit()
    $testsProcessRest.WaitForExit()

    $frameSucceeded = HasDownloadSucceeded($frameProcess)
    $binSucceeded = HasDownloadSucceeded($binProcess)
    $dataSucceeded = HasDownloadSucceeded($dataProcess)
    # $testsSucceeded = HasDownloadSucceeded($testsProcess)

    $downloadSucceeded = $frameSucceeded -And $binSucceeded -And $dataSucceeded
    # -And $testsSucceeded

    $date2 = (Get-Date)
    $timeSpan = $date2 - $date1

    [PsCustomObject]@{
        Succeeded = $downloadSucceeded
        FrameSucceeded = $frameSucceeded
        BinSucceeded = $binSucceeded
        DataSucceeded = $dataSucceeded
        TimeSpan = $timeSpan
    }
    #TestsSucceeded = $testsSucceeded
}

function GetLatestSucceededBuild([string]$buildDefinition)
{
    <#
    .SYNOPSIS
    Gets the UNC drop folder of the last succeeded build.
    Caution: This method assumes that the builds are dropped always to the same drop
    machines. It's recommended to use method CmxGetDropFolderByBuildDefinition instead.
    #>


    if(IsNullOrEmpty($buildDefinition))
    {
        $buildDefinition = $global:BuildDefinition
    }
    $dropMachines = GetDropMachines
    foreach($dropMachine in $dropMachines)
    {
        $dropFolder = "\\$dropMachine\tia\$buildDefinition"
        if(ExistsDirectory($dropFolder))
        {
            $buildFolders = Get-ChildItem $dropFolder | Sort-Object -Property Name -Descending
            foreach($buildFolder in $buildFolders)
            {
                $succeededFile = Join-Path $buildFolder.FullName "CompilationStatus.Succeeded"
                if(ExistsFile($succeededFile))
                {
                    $bestBuildFolder = $buildFolder.FullName
                    return $bestBuildFolder
                }
            }
        }
    }
    return ""
}

function GetDropMachines()
{
    <#
    .SYNOPSIS
    Gets the names of available drop machines.
    #>


    $dropMachines = 
    @(
        "deerls6fsa01.ad001.siemens.net", 
        "deerls6fsa02.ad001.siemens.net",
        "deerls6fsa03.ad001.siemens.net",
        "deerls6fsa04.ad001.siemens.net",
        "deerls6fsa05.ad001.siemens.net"
    );
    return $dropMachines
}

function CreateLogFilePath($logFileName)
{
    return (Join-Path ([IO.Path]::GetTempPath()) "Cmx.DownloadBuild.$logFileName.Log.txt")
}

function StartDownloadProcess($arguments)
{
    <#
    .SYNOPSIS
    Runs a robocopy process with the given arguments.
    #>


    $info = New-Object System.Diagnostics.ProcessStartInfo
    $info.FileName = "robocopy.exe"
    $info.Arguments = $arguments
    $info.RedirectStandardError = $true
    $info.RedirectStandardOutput = $true
    $info.UseShellExecute = $false
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $info
    [void]$p.Start()
    return $p
}

function HasDownloadSucceeded($process)
{
    <#
    .SYNOPSIS
    Checks whether the process succeeded (true) or failed (false). Robocopy treats exit codes in
    range [0, 7] as success codes.
    #>


    return ($process.ExitCode -le 7)
}

function CmxGetDropFolderByBuildDefinition
{
    <#
    .SYNOPSIS
    Get the drop folder of the most recent succeeded xaml build via the REST api.
 
    .PARAMETER BuildDefinition
    The build definition from which to get the drop folder.
    #>


    [CmdletBinding()]
    Param
    (
        [string]$BuildDefinition
    )

    $organizationUrl = $global:TfsUrl
    $tfsProject = "TIA Portal"
    $url = "$organizationUrl/$tfsProject"
    $argumentApiVersion = "api-version=1.0"
    $argumentStatus = "status=Succeeded"
    $argumentTop = "top=1"
    $uri = $url + '/_apis/build/builds?'
    $uri += $argumentApiVersion + '&'
    $uri += 'definition=' + $BuildDefinition + '&'
    $uri += $argumentStatus + '&'
    $uri += $argumentTop + '&'
    $uri += 'ticks=' + (Get-Date).Ticks
    Write-Verbose "uri: $uri"
    $credential = CmxGetWindowsCredential
    if($null -eq $credential)
    {
        Write-Verbose "User credential is missing, so use default credential."
        $response = Invoke-RestMethod -Uri $uri -Method GET -UseDefaultCredentials
    }
    else 
    {
        $response = Invoke-RestMethod -Uri $uri -Method GET -Credential $credential        
    }
    [array]$builds = $response.value
    $dropFolder = $builds[0].dropLocation
    return $dropFolder
}