Runway.Yaml.psm1

<#
    Code in this file will be added to the beginning of the .psm1. For example,
    you should place any using statements here.
#>

Function Get-RwResourceFromCache {
    [cmdletbinding()]
    param (
        [Parameter(
            Mandatory
        )]
        [ValidateSet('Action','Runner')]
        [string]$ResourceType,
        [Parameter(
            Mandatory
        )]
        [string]$Name
    )
    if ($null -eq (Get-Variable -Scope Script -Name 'rwCache' -ErrorAction SilentlyContinue)) {
        $rwCache = @{}
        $rwCache['Action'] = @{}
        $rwCache['Runner'] = @{}
    }
    if ($rwCache[$ResourceType].Keys -notcontains $Name) {
        $rwCache[$ResourceType][$Name] = switch ($ResourceType) {
            'Action' { Get-RwRepository -Name $Name }
            'Runner' { Get-RwRunnerByName -AssetName $Name }
        }
    }
    $rwCache[$ResourceType][$Name]
}
Function New-RwJobSchedule {
    [cmdletbinding()]
    param (
        [int]$RepeatMinutes,
        [string]$Time,
        [string]$Type,
        [string]$WeekDays
    )
    $scheduleSplat = @{
        repeatMinutes = $RepeatMinutes
        Time = $Time
        scheduletype = if ($PSBoundParameters.Keys -contains 'Type') {
                $Type
            } else { 'RunNow' }
        weekdays = $WeekDays
    }
    New-RwJobScheduleObject @scheduleSplat
}
Function Sync-RwResourceYaml {
    [cmdletbinding(
        DefaultParameterSetName = 'FromString'
    )]
    param (
        [Parameter(
            ParameterSetName = 'FromString'
        )]
        [string]$Yaml,
        [Parameter(
            ParameterSetName = 'FromFile'
        )]
        [string]$PathToYaml,
        [switch]$Test
    )

    if ($PSCmdlet.ParameterSetName -eq 'FromFile') {
        $Yaml = Get-Content -Raw $PathToYaml
    }

    $currentUser = Get-RwAuthenticationCurrentUser

    Write-Verbose "Context:`n- Name: $($currentUser.name)`n- Email: $($currentUser.emailAddress)`n- Home Group: $($currentUser.homeContainerId)"

    $resources = ConvertFrom-Yaml $yaml

    # If there are any connectors
    if ($resources.connectors) {
        Write-Information "Found $($resources.connectors.count) connectors"
        Write-Information "Connectors:"

        foreach ($connector in $resources.connectors.Keys) {
            Write-Information "- $connector"

            # Leveraging a cache for the Action names
            if ($resources.connectors[$connector].Keys -contains 'action') {
                if ($resources.connectors[$connector]['action'] -contains 'id') {
                    $actionId = $resources.connectors[$connector]['action']['id']
                } else {
                    $actionId = (Get-RwResourceFromCache -ResourceType Action -Name $resources.connectors[$connector]['action']['name']).Id
                }
            }

            # Leveraging a cache for the Runner names
            if ($resources.connectors[$connector].Keys -contains 'runner') {
                if ($resources.connectors[$connector]['runner'] -contains 'id') {
                    $runnerId = $resources.connectors[$connector]['runner']['id']
                } else {
                    $runnerId = (Get-RwResourceFromCache -ResourceType Runner -Name $resources.connectors[$connector]['runner']['name']).Id
                }
            }

            $splat = @{
                Name     = $connector
                ActionId = $actionId
                RunnerId = $runnerId
                IsHidden = $false
                GroupId  = $currentUser.HomeContainerId
            }

            if ($resources.connectors[$connector].Keys -contains 'parameters') {
                $splat['settings'] = $resources.connectors[$connector]['parameters']
            }

            $conn = Get-RwConnectionByName $connector
            if ($null -ne $conn) {
                Write-Information ' - Updating existing Connector'
                if ($Test.IsPresent) {
                    Write-Information " - Would update existing Connector"
                } else {
                    Set-RwConnection @splat -ConnectionId $conn.Id -ErrorAction Stop
                }
            } else {
                Write-Information ' - Creating new connector'
                if ($Test.IsPresent) {
                    Write-Information " - Would create new Connector"
                } else {
                    New-RwConnection @splat
                }
            }

            # Assign Tags
            if ($resources.connectors[$connector].Keys -contains 'tags') {
                if ($Test.IsPresent) {
                    Write-Information " - Would add tags: $($resources.connectors[$connector]['tags'] -join ',')"
                } else {
                    # Build a set
                    $set = New-RwSet
                    # Add the job to the set
                    if ($null -eq $conn) {
                        $conn = Get-RwConnectionByName -ConnectionName $connector
                    }
                    Add-RwSetToSet -TargetSetId $set -ObjectIds $conn.Id
                    # Add the tags to the set
                    Write-Information " - Adding tags: $($resources.connectors[$connector]['tags'] -join ',')"
                    Add-RwTag -SetId $set -Tags $resources.connectors[$connector]['tags']
                }
            }
        }
    } else {
        Write-Information "No connectors found."
    }

    # If there are any jobs
    if ($resources.jobs) {
        Write-Information "Found $($resources.jobs.count) jobs"
        Write-Information 'Jobs:'

        foreach ($job in $resources.jobs.Keys) {
            Write-Information "- $job"

            # Create job if it doesn't already exist
            $existingJob = Get-RwJobByName $job

            if ($null -ne $existingJob) {
                Write-Verbose ' - Updating existing'
                $existingJob = Get-RwJob -JobId $existingJob.Id
            } else {
                Write-Verbose ' - Creating a new one'
                if ($Test.IsPresent) {
                    Write-Information " - Would create job"
                } else {
                    $newJob = New-RwJob -Name $job -IsEnabled -IsHidden:$false
                    $existingJob = Get-RwJob -JobId $newJob.JobId
                }
            }

            # Assign Schedule
            if ($resources.jobs[$job].Keys -contains 'schedule') {
                Write-Information " - Adding Schedule"

                # Create the schedule object
                $sched = $resources.jobs[$job]['schedule']
                $schedule = New-RwJobSchedule @sched

                # Set the schedule
                if ($Test.IsPresent) {
                    Write-Information " - Would set schedule to $($scheduleSplat | ConvertTo-Json -Compress)"
                } else {
                    Set-RwJobSchedule -JobId $existingJob.Id -Schedule $schedule
                }
            }

            # Assign Actions
            if ($resources.jobs[$job].Keys -contains 'actions') {
                Write-Information ' - Adding Actions'
                $x = 0
                $actions = foreach ($action in $resources.jobs[$job]['actions']) {
                    $x++
                    $actionHt = @{}
                    if ($action.Keys -contains 'id') {
                        $actionHt['RepositoryActionId'] = $action['id']
                    } else {
                        $actionHt['RepositoryActionId'] = (Get-RwResourceFromCache -ResourceType Action -Name $action['name']).Id
                    }
                    Write-Information " - $x`: '$($action['name'])'"
                    Write-Verbose "Associating '$($action['name'])' to '$($actionHt['RepositoryActionId'])'"
                    if ($action.Keys -contains 'parameters') {
                        Write-Information " - Adding parameters"
                        $actionHt['Settings'] = $action['parameters']
                    }

                    if ($action.Keys -contains 'connector') {
                        Write-Information " - Adding connector"
                        if ($action['connector'].Keys -contains 'id') {
                            $actionHt['ConnectionId'] = $action['connector']['id']
                        } elseif ($action['connector'].Keys -contains 'name') {
                            $actionHt['ConnectionId'] = (Get-RwConnectionByName -ConnectionName $action['connector']['name']).Id
                        }
                    }

                    $actionHt
                }
                if ($Test.IsPresent) {
                    Write-Information " - Would Update Actions"
                } else {
                    Set-RwJobAction -JobId $existingJob.Id -Request $actions
                }
            }

            # Assign Runners
            if ($resources.jobs[$job].Keys -contains 'runners') {
                Write-Information ' - Adding Runners'
                $newMembers = if ($resources.jobs[$job]['runners'].Keys -contains 'names') {
                    Write-Information " - Adding runners by name"
                    (Get-RwRunnerByName -AssetName $resources.jobs[$job]['runners']['names']).AssetId
                } elseif ($resources.jobs[$job]['runners'].Keys -contains 'tags') {
                    Write-Information " - Adding Runners by tags: '$($resources.jobs[$job]['runners']['tags'] -join "','")'."
                    (Get-RwEndpointByTag -Tags $resources.jobs[$job]['runners']['tags']).Id
                }

                Write-Information " - Found $($newMembers.Count) total Runners that should be assigned"

                if ($Test.IsPresent) {
                    Write-Information " - Would update membership"
                } else {
                    Sync-RwSetMembership -Members $newMembers -SetId $existingJob.EndpointSetId
                }
            }

            # Assign Tags
            if ($resources.jobs[$job].Keys -contains 'tags') {
                if ($Test.IsPresent) {
                    Write-Information " - Would add tags: $($resources.jobs[$job]['tags'] -join ',')"
                } else {
                    # Build a set
                    $set = New-RwSet
                    # Add the job to the set
                    Add-RwSetToSet -TargetSetId $set -ObjectIds $existingJob.Id
                    # Add the tags to the set
                    Write-Information " - Adding tags: $($resources.jobs[$job]['tags'] -join ',')"
                    Add-RwTag -SetId $set -Tags $resources.jobs[$job]['tags']
                }
            }
        }
    } else {
        Write-Information "No jobs found."
    }
}
Function Sync-RwSetMembership {
    [CmdletBinding()]
    param (
        [string[]]$Members,
        [string]$SetId
    )
    $existingMembers = Get-RwSetMember -SetId $SetId

    Write-Verbose "Current set membership count: $($existingMembers.Count)"

    # Finding any existing members that don't meet the filter
    $toRemove = [System.Collections.Generic.List[string]]::new()
    $toAdd = [System.Collections.Generic.List[string]]::new()
    foreach ($existingMember in $existingMembers.Items) {
        if ($newMembers.Items.Id -notcontains $existingMember.Id) {
            #Write-Verbose "Will remove $($existingMember.Id)"
            $toRemove.Add($existingMember.Id)
        }
    }

    # Find any matching members that need to be added
    foreach ($newMember in $Members) {
        if ($existingMembers.Items.Id -notcontains $newMember) {
            #Write-Verbose "Will add $($newMember)"
            $toAdd.Add($newMember)
        }
    }

    # Remove unneeded runners
    if ($toRemove.Count -gt 0) {
        Write-Verbose "Removing $($toRemove.Count) Runners from the set"
        Remove-RwSetFromSet -TargetSetId $SetId -ObjectIds $toRemove | Out-Null
    }

    # Add those runners to the job set
    if ($toAdd.Count -gt 0) {
        Write-Verbose "Adding $($toRemove.Count) Runners to the set"
        Add-RwSetToSet -TargetSetId $SetId -ObjectIds $toAdd | Out-Null
    }
}
<#
    Code in this file will be added to the end of the .psm1. For example,
    you should set variables or other environment settings here.
#>