scripts/Invoke-Step.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
function Invoke-Step {
  [CmdletBinding()]
  param (
    [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
    [object]$step,

    [Parameter(Position = 1, Mandatory = $false)]
    [hashtable]$config = (Coalesce (Peek-Config), @{}),

    [Parameter(Position = 2, Mandatory = $false)]
    [string]$work_dir = ''
  )
  process {
    $ErrorActionPreference = 'Continue'

    try {
      "Invoke-Step:In:$(@{'$_'=$_} | ConvertTo-Yaml)" | f-log-dbg
      $step = $_ = $_ | Build-Step
      "Invoke-Step:Build-Step:$(@{'$_'=$_} | ConvertTo-Yaml)" | f-log-dbg

      if ($step['$context'].template_key) {
        # add alias to simplify templates definition
        New-Variable -Name $step['$context'].template_key -Value $step -Force
      }

      if ($work_dir) {
        # Since actual execution is performed in the $step that can contain it's own .work_dir property
        # override it only if the $step.work_dir is empty
        if (-not $step.work_dir) {
          $step.work_dir = $work_dir
        }
      }

      ${global:pwshake-context}.hooks['invoke-step'].onEnter | ForEach-Object {
        "Invoke-Step:try:{$_}" | f-log-dbg; Invoke-Expression $_
      }

      if (-not (Invoke-Expression $step.when)) {
        "`tBypassed because of: [$($step.when)] = $(Invoke-Expression $step.when)" | f-log-info | Out-Null
        return;
      }

    ${log-Out} = @(); ${log-Err} = @(); $global:LASTEXITCODE = 0
      "Invoke-Step:powershell: {`n$($step.powershell)}" | f-log-dbg
      if ($config.attributes.pwshake_dry_run) {
        "`tBypassed because of -DryRun: $($config.attributes.pwshake_dry_run)" | f-log-info
        return;
      }
      Invoke-Expression $step.powershell *>&1 -ErrorVariable log-Err | Tee-Object -Variable log-Out `
      | f-log-min
      if ((($LASTEXITCODE -ne 0) -or (-not $?)) -and ($step.on_error -eq 'throw')) {
        $lastErr = (${log-Err} + ${log-Out}) | Where-Object { $_ -is [Management.Automation.ErrorRecord] } | Select-Object -Last 1
        if (-not $lastErr) {
          $lastErr = "$($step.name) failed."
        }
        throw $lastErr
      }
    }
    catch {
      $_ | f-log-err
      if ($step.on_error -eq 'throw') {
        (Peek-Context).caught = $true
        throw $_
      }
    }
    finally {
      ${global:pwshake-context}.hooks['invoke-step'].onExit | ForEach-Object {
        "Invoke-Step:finally:{$_}" | f-log-dbg; Invoke-Expression $_
      }
    }
  }
}