# OCL Syntax Reference for Process Templates ## Grammar Rules OCL (Octopus Configuration Language) follows a strict format. The EBNF grammar is defined at https://github.com/OctopusDeploy/Ocl. ### Core Rules - **Name, `=`, and value** must be on the same line - **Block name, labels, and `{`** must be on the same line - **Closing `}`** must be on its own line (except empty blocks like `value "default" {}`) - **Strings** use double quotes, cannot contain unescaped `"` - **Multi-line strings** use heredoc: `<<-EOT` / `EOT` - **Arrays** use `["item1", "item2"]` - **Dictionaries** use `{ key = "value" }` (one entry per line inside braces) ### Name Restrictions Template and step names can only contain: letters, numbers, periods, commas, dashes, underscores, hashes. **Invalid:** `Run Security Scan (SAST/SCA)` — parentheses and slashes not allowed **Valid:** `Run Security Scan - SAST and SCA` ## Process Template File Structure ```hcl name = "Template Display Name" description = "What this template does" # Parameters (consumed by projects, referenced in steps) parameter "param_name" { display_settings = { Octopus.ControlType = "SingleLineText" } help_text = "Description for UI" label = "Display Label" value "default_value" {} # Optional default } # Worker pool parameter (REQUIRED — every template needs this) parameter "worker_pool" { display_settings = { Octopus.ControlType = "WorkerPool" } help_text = "Worker pool for server-side steps" label = "Worker Pool" } # Steps (executed in order) step "step-slug" { name = "Step Display Name" start_trigger = "StartAfterPrevious" # or "StartWithPrevious" action { action_type = "Octopus.Script" properties = { Octopus.Action.RunOnServer = "true" Octopus.Action.Script.ScriptSource = "Inline" Octopus.Action.Script.Syntax = "PowerShell" Octopus.Action.Script.ScriptBody = <<-EOT Write-Host "Hello from #{Octopus.Project.Name}" EOT OctopusUseBundledTooling = "False" } worker_pool_variable = "worker_pool" } } ``` ## Parameter Types | Type | `Octopus.ControlType` | Can Default | Notes | |------|----------------------|-------------|-------| | Single-line text | `SingleLineText` | Yes | Most common for string values | | Multi-line text | `MultiLineText` | Yes | For scripts, YAML, JSON | | Sensitive | `Sensitive` | Yes | Encrypted in DB | | Checkbox | `Checkbox` | Yes | Boolean | | Dropdown | `Select` | Yes | Predefined options | | Target Tags | `TargetTags` | No | For Kubernetes/deployment targets | | Worker Pool | `WorkerPool` | No | **Required on every template** | | Package | (package) | No | Container image references | | Environments | (environments) | No | | | Channels | (channels) | No | | ### Default Values ```hcl # String default parameter "cloud_target" { display_settings = { Octopus.ControlType = "SingleLineText" } help_text = "Cloud provider" label = "Cloud Target" value "gcp" {} # Default value in empty block } # No default (must be set by consuming project) parameter "target_tags" { display_settings = { Octopus.ControlType = "TargetTags" } help_text = "K8s target tags" label = "Target Tags" } ``` ## Step Structure ### Inline Script Step (most common in process templates) ```hcl step "step-slug" { name = "Display Name" start_trigger = "StartAfterPrevious" action { action_type = "Octopus.Script" properties = { Octopus.Action.RunOnServer = "true" Octopus.Action.Script.ScriptSource = "Inline" Octopus.Action.Script.Syntax = "PowerShell" # or "Bash" Octopus.Action.Script.ScriptBody = <<-EOT # PowerShell script here $project = $OctopusParameters['Octopus.Project.Name'] Write-Host "Deploying $project" EOT OctopusUseBundledTooling = "False" } worker_pool_variable = "worker_pool" } } ``` ### Deployment Target Step (runs on targets, not server) ```hcl step "deploy-step" { name = "Deploy to K8s" start_trigger = "StartAfterPrevious" properties = { Octopus.Action.TargetRoles = "#{target_tags}" # References parameter } action { action_type = "Octopus.Script" properties = { Octopus.Action.RunOnServer = "false" # Runs on target Octopus.Action.Script.ScriptSource = "Inline" Octopus.Action.Script.Syntax = "PowerShell" Octopus.Action.Script.ScriptBody = <<-EOT Write-Host "Deploying to target" EOT OctopusUseBundledTooling = "False" } worker_pool_variable = "worker_pool" } } ``` ### Kubernetes Raw YAML Step ```hcl step "k8s-deploy" { name = "Apply Kubernetes YAML" properties = { Octopus.Action.TargetRoles = "#{target_tags}" } action { action_type = "Octopus.KubernetesDeployRawYaml" properties = { Octopus.Action.GitRepository.FilePathFilters = "#{{yaml_path}}" Octopus.Action.GitRepository.Source = "External" Octopus.Action.Kubernetes.DeploymentTimeout = "180" Octopus.Action.Kubernetes.ResourceStatusCheck = "True" Octopus.Action.Kubernetes.ServerSideApply.Enabled = "True" Octopus.Action.Kubernetes.ServerSideApply.ForceConflicts = "True" Octopus.Action.KubernetesContainers.Namespace = "#{namespace}" Octopus.Action.Script.ScriptSource = "GitRepository" } worker_pool_variable = "worker_pool" git_dependencies { default_branch = "main" file_path_filters = ["#{yaml_path}"] git_credential_type = "Anonymous" repository_uri = "#{repo_url}" } } } ``` ## Referencing Variables ### Octopus System Variables Use `$OctopusParameters['Variable.Name']` in PowerShell scripts: ```powershell $project = $OctopusParameters['Octopus.Project.Name'] $release = $OctopusParameters['Octopus.Release.Number'] $env = $OctopusParameters['Octopus.Environment.Name'] $channel = $OctopusParameters['Octopus.Release.Channel.Name'] ``` ### Template Parameters In OCL properties (outside scripts): `#{parameter_name}` In PowerShell scripts: `$OctopusParameters['parameter_name']` ```hcl # In OCL properties Octopus.Action.TargetRoles = "#{target_tags}" # In script body $cloudTarget = $OctopusParameters['cloud_target'] ``` **Double-bracing escape:** In some OCL properties, use `#{{param}}` to escape Octopus variable substitution: ```hcl Octopus.Action.GitRepository.FilePathFilters = "#{{yaml_path}}" ``` ### Output Variables Set output variables from scripts for use in later steps: ```powershell Write-Host "##octopus[setVariable name='CoveragePercent' value='87']" ``` Read in subsequent steps: ```powershell $coverage = $OctopusParameters['Octopus.Action[run-unit-tests].Output.CoveragePercent'] ``` ## Channel Scoping Scope steps to specific channels (for dual-image patterns): ```hcl action { action_type = "Octopus.Script" channels = ["non-prod"] # Only runs in this channel properties = { ... } } ``` ## Environment Scoping ```hcl action { environments = ["production"] # Only in prod excluded_environments = ["development"] # Not in dev } ``` ## Step Properties Reference | Property | Type | Values | Default | |---|---|---|---| | `step.condition` | enum | `Success`, `Failure`, `Always`, `Variable` | `Success` | | `step.start_trigger` | enum | `StartAfterPrevious`, `StartWithPrevious` | `StartAfterPrevious` | | `step.package_requirement` | enum | `LetOctopusDecide`, `BeforePackageAcquisition`, `AfterPackageAcquisition` | `LetOctopusDecide` | | `action.channels` | string[] | channel slugs | all | | `action.environments` | string[] | environment slugs | all | | `action.excluded_environments` | string[] | environment slugs | none | | `action.is_disabled` | bool | | `False` | | `action.is_required` | bool | | `False` | | `action.notes` | string | step description | | | `action.worker_pool` | string | worker pool slug | | | `action.worker_pool_variable` | string | variable name | | ## References - [OCL Format Specification](https://octopus.com/docs/projects/version-control/ocl-file-format) - [Config as Code Reference](https://octopus.com/docs/projects/version-control/config-as-code-reference) - [OCL Grammar (EBNF)](https://github.com/OctopusDeploy/Ocl)