Sort order with Octopus.Action

I’m trying to implement an Email Notification step that includes the list of deployment steps and whether or not they are pending or skipped by the user. This works perfectly fine in one project but then is sorted incorrectly in another project. The email template is shared through a variable so it’s the same exact code building the email body. Any know issues with sorting or any tips to help mitigate this?

Here’s an example of the incorrect sorting from the email body.

image

Here’s the script that creates it.

<h3>Deployment Plan</h3>
 <ul>
  #{each action in Octopus.Action}
    #{if action.IsSkipped}
      <li>#{action.Number}. #{action.Name} - (Excluded)</li>
    #{else}
      <li>#{action.Number}. #{action.Name} - (Pending)</li>
    #{/if}
  #{/each}
 </ul>

Hi @tfbryan,

Thanks for reaching out!

I’ve been playing around with this today and haven’t found a super elegant way to solve this. The issue is that “Octopus.Action” is a Collection (Dictionary with HashTable) which doesn’t maintain order.

I’ve modified the script you provided so that it will check the Action.Number before writing the output, and can be extended for however many Actions you’d like outputted. I would prefer to do this more gracefully but it does work based on my tests!

#{each action in Octopus.Action} 
#{if action.Number == "1"}<li>#{action.Number}. #{action.Name} - #{if action.IsSkipped} (Excluded) #{else} (Pending) #{/if} </li>
#{/if}
#{/each}

#{each action in Octopus.Action} 
#{if action.Number == "2"}<li>#{action.Number}. #{action.Name} - #{if action.IsSkipped} (Excluded) #{else} (Pending) #{/if} </li>
#{/if}
#{/each}

I’ve started some internal discussion about getting Octostache extended so that this is easier to achieve but that should at least get them ordered in the meantime.

Feel free to let me know if you have any questions!

Best Regards,

Issue has been fixed. Thanks for the help

Uhh yeah this looks horribly inefficient and painful. One of my projects has over 60 steps not including child steps, not to mention that projects change over time and trying to keep up with this would not scale.

Hi Todd,

I agree it’s not a great solution and there is definitely a better approach to be found here. I’ll keep diving into this and keep you posted when I’ve come up with a better workaround.

Best Regards,

Hi @tfbryan,

I have finally managed to get this working for any number of steps! The process does require an additional step to create an Output variable which is the list of steps in order.

The following script is defined in a Run a Script step which outputs a JSON string with the required details in order.

Run A Script - “Create Sorted Action List”

$actions = $OctopusParameters.Keys | Where-Object { $_ -like "Octopus.Action``[*``].Name" } | ForEach-Object { 
$name = $OctopusParameters[$_]
$number = $OctopusParameters["Octopus.Action[$name].Number"]
if ($OctopusParameters["Octopus.Action[$name].IsSkipped"]) {$skipped = "Skipped"}
else { $skipped = "Pending" }
@{number = $number; name = $name; skipped = $skipped; }
} | Sort-Object {$_.number} | ConvertTo-Json

Set-OctopusVariable -name "OrderedActions" -value $actions

The email template step then references this variable:

<h3>Deployment Plan</h3>
<ul>
#{each action in Octopus.Action[Create Sorted Action List].Output.OrderedActions} 
<li>#{action.number}. #{action.name} - #{action.skipped}</li>
#{/each}
</ul>

Feel free to let me know if you have any questions or would like an explanation of any component.

Best Regards,

1 Like