Microsoft.PowerPlatform.DevOps.psm1

[cmdletbinding()]
Param()

$global:devops_OldVerbose = $VerbosePreference
$VerbosePreference = $global:devops_Verbose

Write-Verbose "Importing Functions"

# Import everything in these folders
foreach ($folder in @('Private', 'Scripts')) {
    
    $root = Join-Path -Path $PSScriptRoot -ChildPath $folder
    if (Test-Path -Path $root) {
        Write-Verbose "processing folder $root"
        $files = Get-ChildItem -Path $root -Filter *.ps1

        # dot source each file
        $files | where-Object { $_.name -NotLike '*.Tests.ps1' } | 
        ForEach-Object { Write-Verbose "dot loading Library $($_.name) "; . $_.FullName }
    }
}

$global:devops_ToolPath = $PSScriptRoot 

if (!(Test-Path "$env:APPDATA\Microsoft.PowerPlatform.DevOps")) {
    New-Item -Path "$env:APPDATA\Microsoft.PowerPlatform.Devops" -ItemType Directory
}
if (!(Test-Path "$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")) {
    Copy-Item (Join-Path $PSScriptRoot "\devopsConfig.json") -Destination "$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json"
}

function Show-ConfigMenu {
    Get-ConfigMenu
    $configSelection = Read-Host "Selection"
    try {
        switch ($configSelection) {
            'G' {
                try {
                    code $env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json    
                }
                catch {
                    try {
                        notepad $env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json    
                    }
                    catch {
                        try {
                            nano $env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json    
                        }
                        catch {
                            Write-Error $_
                            Write-Host ""
                            Write-Host "Please re-run Pre-requisite installation" -ForegroundColor Green
                            pause
                        }  
                    }  
                }              
            } 'P' {
                try {
                    code $global:devops_projectLocation\$global:devops_gitRepo.json        
                }
                catch {
                    try {
                        notepad $global:devops_projectLocation\$global:devops_gitRepo.json        
                    }
                    catch {
                        try {
                            nano $global:devops_projectLocation\$global:devops_gitRepo.json        
                        }
                        catch {
                            Write-Error $_ 
                            Write-Host ""
                            Write-Host "Please re-run Pre-requisite installation" -ForegroundColor Green
                            pause                                                
                        }                                                
                    }                    
                }
                
            } 'A' {
                Set-AzureKeyVault
            } 'C' {
                Set-ServicePrincipal
            } 'L' {
                $global:devops_HasDataverseLogin = $false
                Get-DataverseLogin
            } 'R' {
                Get-AzureAccounts("Azure DevOps git Token")
                pause

            } 'D' {
                $REPO_URL = git remote get-url origin
                Write-Host "git URL is $REPO_URL" 

                git config --unset http.$REPO_URL.extraHeader
                pause
            } 'Z' {
                Write-Host "Clearing Azure (AZ CLI) Account Cache"
                az account clear
                pause
            } 'U' {
                Show-ToolingMenu
            }
        }            
    }
    catch {
        Write-Host $_
        pause
    }
}

function Show-BranchMenu {
    Get-BranchMenu
    $branchSelection = Read-Host "Selection"
    try {
        switch ($branchSelection) {
            'S' {
                try {

                    $branches = git branch -a
                    do {
                        $sel = Invoke-Menu -MenuTitle "---- Please Select your Branch ------" -MenuOptions $branches          
                    } until ($sel -ge 0)
                    $selectedBranch = $branches[$sel] -Replace "\*", ""
                    $selectedBranch = $branches[$sel] -Replace " ", ""  
                    if ($selectedBranch.Contains("origin")) {
                        git checkout --track $selectedBranch
                    }                  
                    else {
                        git checkout $selectedBranch    
                    }                    
                    git pull
                    $global:devops_Branch = git branch --show-current
                    pause
                }
                catch {
                    Write-Error $_
                    Write-Host ""
                    pause
                }              
            } 'C' {
                try {

                    $branchName = Read-Host "Enter the Name for your Branch"
                    git branch $branchName
                    git checkout $branchName
                    git push -u origin $branchName
                    $global:devops_Branch = git branch --show-current
                    pause   
                }
                catch {
                    Write-Error $_ 
                    Write-Host ""
                    pause                                                
                }                                                
            }  'U' {

                $branches = git branch
                do {
                    $sel = Invoke-Menu -MenuTitle "---- Select Branch to update from ------" -MenuOptions $branches          
                } until ($sel -ge 0)
                $selectedBranch = $branches[$sel] -Replace "\*", ""
                $selectedBranch = $branches[$sel] -Replace " ", ""  
                git merge $selectedBranch
                pause   
            } 'P' {
                git push
                pause
            } 'L' {
                git pull origin $global:devops_Branch
                pause
            }
        }
    }
    catch {
        Write-Error $_ 
        pause      
    }
}

function Show-ToolingMenu {
    Get-ToolingMenu
    $toolSelection = Read-Host "Selection"
    try {
        switch ($toolSelection) {
            'P' {
                try {
                    Update-PAC
                }
                catch {
                    Write-Error $_
                    Write-Host ""
                    pause
                }              
            } 'X' {
                try {
                    Update-XrmContext
                }
                catch {
                    Write-Error $_ 
                    Write-Host ""
                    pause                                                
                }                                                
            }  'D' {
                try {
                    Update-XrmDefinitelyTyped
                }
                catch {
                    Write-Error $_ 
                    Write-Host ""
                    pause                                                
                }  
            } 'C' {
                try {
                    Update-ConfigMigration
                }
                catch {
                    Write-Error $_ 
                    Write-Host ""
                    pause                                                
                }  
            } 
        }
    }
    catch {
        Write-Error $_ 
        pause      
    }
}
    

function Invoke-PowerPlatformDevOps {
    Param(
        [string] [Parameter(Mandatory = $false)] $PreLoadProjectPath = "",
        [string] [Parameter(Mandatory = $false)] $PreLoadedProjectName = "",
        [string] [Parameter(Mandatory = $false)] $PreSelection = "",
        [bool] [Parameter(Mandatory = $false)]$DebugMode = $false
    )

    <#
        .SYNOPSIS
        Invokes and initiate the Powerplatform DevOps toolkit
 
        .DESCRIPTION
        Manage your Powerplatform Development environment
 
        .PARAMETER PreLoadProjectPath
        Specifies the file name.
 
        .PARAMETER PreSelection
        Specifies the extension. "Txt" is the default.
 
        .INPUTS
        None.
 
        .OUTPUTS
        None.
 
        .EXAMPLE
        PS> Invoke-PowerplatformDevops
         
        .EXAMPLE
        PS> ppdo
                 
        .LINK
        Online version: https://github.com/dylanhaskins/Microsoft.PowerPlatform.DevOps.Documentation
         
    #>

    $datePart = (Get-Date).ToString("yyyy_MM_dd_hhtt")
    Start-Transcript -Append -Path $env:APPDATA\Microsoft.PowerPlatform.DevOps\Logs\$($datePart)_log.txt

    if (!$DebugMode) {
        Write-Host "Checking for updated versions...."
        if ((Get-Module -Name PowerShellGet).Version -gt [version]"2.0.0") {
            $latestVersion = Get-PublishedModuleVersion -Name Microsoft.PowerPlatform.DevOps   
        }
        else {
            $latestVersion = Get-PublishedModuleVersion -Name Microsoft.PowerPlatform.DevOps
        }
        $currentVersion = (Get-Module -Name Microsoft.PowerPlatform.DevOps).Version
        if ($latestVersion -gt $currentVersion) {
            Write-Host "Updating to $latestVersion"
            Update-Module Microsoft.PowerPlatform.DevOps    
            Write-Host "Updated to $latestVersion, please restart the tool for it to take effect."                
        }
    }

    Write-Verbose "Clearing devops_ Global Variables"
    Clear-Variable devops_* -Scope Global

    Install-ConfigMigrationModule
    Install-XrmModule
    Install-PowerAppsAdmin
    Install-PowerAppsCheckerModule

    if ($PreLoadProjectPath -ne "") {
        if ((Test-Path -Path "$PreLoadProjectPath\$PreLoadedProjectName.json")) {
            $global:devops_projectLocation = "$PreLoadProjectPath"
    
            $global:devops_projectFile = Get-Content ("$PreLoadProjectPath\$PreLoadedProjectName.json") | ConvertFrom-Json
            $global:devops_gitRepo = $global:devops_projectFile.gitRepo
            Set-Location  $global:devops_projectLocation
        }  
    }

    Write-Host ""
    [console]::ForegroundColor = "White"
    do {
        Get-MainMenu

        if ($PreSelection -ne "") {
            $selection = $PreSelection
            $global:devops_devMode = $true
            $PreSelection = ""
            Write-Host "Performing your Automated Selection ..."
            Start-Sleep -Seconds 2
        }
        else {
            $selection = Read-Host "Please make a selection"            
        }
        try {
            switch ($selection) {
                '1' {
                    Install-PreReqs
                } '2' {
                    Add-Project
                } '3' {
                    Connect-SourceControl
                } '3a' {
                    Set-ServicePrincipal
                } '4' {
                    Add-CICDEnvironment
                } 'A' {
                    Add-Solution
                } 'M' {
                    Select-Solution
                } 'S' {
                    Sync-Solution
                } 'V' {
                    Show-SolutionChanges
                } 'T' {
                    $CreateOrSelectEnv = Read-Host -Prompt "Target Environment : Would you like to [P]rovision a new Power Platform Environment ? or [S]elect an Existing One (Default [S])"
                    if ($CreateOrSelectEnv -eq "P") {
                        Add-Environment
                        Invoke-ConfigureTargetEnvironment
                    }
                    else {
                        Invoke-ConfigureTargetEnvironment
                    }                
                } 'A' {
                    # Enable-AzureDeploy
                } 'F' {
                    # Enable-FunctionApp
                } 'U' {
                    Write-Host "Checking for updated versions...."
                    $latestVersion = (Find-Module Microsoft.PowerPlatform.DevOps -Repository "PSGallery").Version
                    if ($latestVersion -gt $global:devops_version) {
                        Update-Module Microsoft.PowerPlatform.DevOps    
                        Write-Host "Updated to $latestVersion, please restart the tool for it to take effect."                
                    }
                } 'O' {
                    Invoke-OpenSolution
                } 'C' {
                    Show-ConfigMenu
                } 'R' {
                    Get-DataverseLogin
                    Get-DeployEnvironments                    
                } 'B' {
                    Show-BranchMenu
                } 'D' {
                    Invoke-OpenSolutionInVSCode
                }
            }
            Write-Host ""
        }
        catch {
            Write-Host $_
        }

    }
    until ($selection -eq 'q')
    $VerbosePreference = 'SilentlyContinue'
    Clear-Variable devops_* -Scope Global
    if (!$VerbosePreference -eq "Continue") {
        Clear-Host    
    
    }
    Stop-Transcript
    #return
    Stop-Process -Id $PID
}

function Test-IsGuid {
    [OutputType([bool])]
    param
    (
        [Parameter(Mandatory = $true)]
        [string]$StringGuid
    )
 
    $ObjectGuid = [System.Guid]::empty
    return [System.Guid]::TryParse($StringGuid, [System.Management.Automation.PSReference]$ObjectGuid) # Returns True if successfully parsed
}

function Start-PPDODocker {
    Param(
        [string] [Parameter(Mandatory = $true)] $PAT,
        [string] [Parameter(Mandatory = $true)] $ADOOrg,
        [string] [Parameter(Mandatory = $true)] $ADOProject
    )
    & $PSScriptRoot\Docker\go.ps1 -PAT $PAT -ADOOrg $ADOOrg -ADOProject $ADOProject
}

Export-ModuleMember -Function 'Invoke-PowerPlatformDevOps' -Alias ppdo
Export-ModuleMember -Function 'Test-IsGuid'
Export-ModuleMember -Function 'Start-DeploySolution'
Export-ModuleMember -Function 'Start-SolutionChecker'
Export-ModuleMember -Function 'Start-PPDODocker'
Export-ModuleMember -Function 'Invoke-ExportSolution'
New-Alias -Name ppdo -Value Invoke-PowerPlatformDevOps -Scope Global
New-Alias -Name Deploy-Solution -Value Start-DeploySolution -Scope Global
New-Alias -Name Export-Solution -Value Invoke-ExportSolution -Scope Global
New-Alias -Name ppdo-docker -Value Start-PPDODocker -Scope Global