# Octopus Deploy Process Templates Best practices for creating and managing Octopus Deploy process templates using OCL (Octopus Configuration Language) in Platform Hub. ## Key Concepts - **Step templates** (action templates) are reusable individual steps, created via API or UI, stored in a space's library - **Process templates** are reusable multi-step deployment processes, stored as OCL files in Platform Hub's Git repo - **Project templates** compose process templates into full project configurations (feature coming soon) - Process templates live in `.octopus/process-templates/.ocl` in the Platform Hub Git repo - Projects consume process templates via `process_template` blocks in their `deployment_process.ocl` ## OCL File Structure ### Process Template File ```hcl name = "Deploy to Kubernetes - Helm" description = "Standard Helm-based Kubernetes deployment with pre-validation and smoke tests" # Parameters — values supplied by consuming projects parameter "target_tags" { display_settings = { Octopus.ControlType = "TargetTags" } help_text = "Kubernetes target tags" label = "Target Tags" } parameter "cloud_target" { display_settings = { Octopus.ControlType = "SingleLineText" } help_text = "Cloud provider (gcp, aws, azure)" label = "Cloud Target" value "gcp" {} # default value } # Steps — ordered deployment steps step "deploy-helm" { name = "Deploy via Helm" properties = { Octopus.Action.TargetRoles = "#{target_tags}" } action { action_type = "Octopus.Script" properties = { Octopus.Action.Script.ScriptSource = "Inline" Octopus.Action.Script.Syntax = "PowerShell" Octopus.Action.Script.ScriptBody = "Write-Host 'Deploying...'" } worker_pool_variable = "" } } ``` ### How Projects Consume Process Templates In a project's `deployment_process.ocl`: ```hcl process_template "deploy-app" { name = "Deploy Application" process_template_slug = "deploy-to-kubernetes-helm" version_mask = "1.X" # auto-update minor/patch parameter "target_tags" { value = "kubernetes,production" } parameter "cloud_target" { value = "aws" } } ``` ## OCL Syntax Rules From the EBNF grammar (https://github.com/OctopusDeploy/Ocl): - **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: `<<-EOF` / `EOF` (indented variant) - **Arrays** use `["item1", "item2"]` - **Dictionaries** use `{ key = value }` (one entry per line inside braces) ## Referencing Step Templates Step templates are referenced by **ID and version** in the action's properties, NOT by name: ```hcl step "run-tests" { name = "Run Unit Tests" action { # Reference a step template instead of action_type properties = { Octopus.Action.Template.Id = "ActionTemplates-62" Octopus.Action.Template.Version = "1" # Step template parameter values Language = "go" CloudTarget = "gcp" } worker_pool_variable = "" } } ``` When NOT using a step template, define `action_type` directly: ```hcl action { action_type = "Octopus.Script" properties = { ... } } ``` ## Channel Scoping Scope steps to specific channels using the `channels` attribute on the action block. Uses **channel slugs** (auto-generated from names): ```hcl action { action_type = "Octopus.Script" channels = ["non-prod"] # only runs in non-prod channel properties = { ... } } ``` ## Package References ```hcl # Container image for worker execution container { feed = "registered-dockerhub" # feed slug, not ID image = "octopusdeploy/worker-tools:ubuntu.22.04" } # Package reference in a step packages "MyPackage" { acquisition_location = "NotAcquired" # Server | ExecutionTarget | NotAcquired feed = "platformhub-non-prod" # feed slug package_id = "paul-oreilly-octopus/nonprod/listing-service" properties = { SelectionMode = "immediate" } } ``` ## Parameter Types | Control Type | `Octopus.ControlType` Value | Can Have Default | |---|---|---| | Single-line text | `SingleLineText` | Yes | | Multi-line text | `MultiLineText` | Yes | | Sensitive/password | `Sensitive` | Yes (encrypted) | | Checkbox | `Checkbox` | Yes | | Dropdown | `Select` | Yes | | AWS/Azure/GCP Account | `AWSAccount` etc. | Yes | | Worker Pool | (worker pool) | No | | Package | (package) | No | | Target Tags | `TargetTags` | No | | Environments | (environments) | No | | Channels | (channels) | No | ## 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 | | ## Versioning - Process templates use **semantic versioning** (major.minor.patch) - `version_mask = "1.X"` in consuming projects auto-updates on minor/patch changes - **Major version bumps** require explicit upgrade by consuming projects - Keep major bumps for breaking changes (parameter renames, step removals) - Minor/patch for new optional parameters, script improvements, bug fixes ## Dual-Image / Multi-Registry Channel Pattern When a project builds distinct images to separate registries per environment tier (e.g., non-prod vs prod), model each registry as its own **Feed** and create **one channel-scoped deployment step per feed**. Two channel-scoped steps are cleaner than a single step with version rules, because differing `PackageId` values (`org-nonprod/app` vs `org-prod/app`) cannot both be satisfied by a single step's package reference. ```hcl step "deploy-nonprod" { action { channels = ["non-prod"] packages "app" { feed = "registry-nonprod" package_id = "org-nonprod/app" } } } step "deploy-prod" { action { channels = ["prod"] packages "app" { feed = "registry-prod" package_id = "org-prod/app" } } } ``` ## Release Creation: CI-Driven vs Feed Triggers Octopus feed triggers silently ignore non-SemVer Docker tags (e.g., `sha-abc12345`) and poll on a ~3-minute interval. For SHA-tagged workflows or any non-SemVer scheme: - **Preferred:** have CI `POST /api/releases` directly after pushing the image. This is instant, avoids simultaneous-trigger race conditions on `UQ_ReleaseVersionUnique`, and works with any tag format. - **Alternative:** tag with SemVer plus a timestamp build number (`1.2.3+YYYYMMDDHHMM`) for guaranteed uniqueness without needing external state. Feed triggers remain fine for pure-SemVer tag schemes. ## Channel Version Rules and Enforcement Channel version rules require **either a version range or a pre-release tag** — they cannot be empty. For non-SemVer tagging schemes, remove all rules (`Rules: []`) and rely on step channel-scoping (`action.channels`) for enforcement instead. The **default channel** on any project cannot be deleted; either leave it unused or promote another channel to default before removing it. ## Auto-Promoting Lifecycles for Hands-Free Demos / PoCs To demonstrate a full CI-to-deployed flow, set lifecycle phases to auto-deploy by moving environments from `OptionalDeploymentTargets` to `AutomaticDeploymentTargets`. Pair a non-prod lifecycle (Dev → Staging) with a prod lifecycle (Staging → Production) so each channel's releases promote automatically once created. ## Gotchas 1. **Step templates are space-scoped.** Process templates in Platform Hub cannot reference `ActionTemplates-*` IDs from other spaces. If you need reusable steps, use inline `action_type = "Octopus.Script"` in the process template OCL. Step templates are useful within a single space's projects, but not for cross-space process templates. 2. **Process template names** cannot contain parentheses, slashes, or ampersands — only letters, numbers, periods (`.`), commas (`,`), dashes (`-`), underscores (`_`), and hashes (`#`). 3. **Heredoc for multi-line scripts** — use `<<-EOT` / `EOT` for PowerShell scripts that contain double quotes. The `-` prefix allows indented closing tags. 4. **Every step needs a worker pool.** Process templates must have a `worker_pool` parameter (type `WorkerPool`), and every action must set `worker_pool_variable = "worker_pool"` referencing it. Without this, the template will fail to parse with "A step must specify a worker pool parameter". 5. **Publishing and sharing is UI-only.** Process template sharing (which spaces can see/use a template) is stored in the Octopus database, not in Git/OCL. You must publish and share each template through the UI. There is no API or CLI for this currently. 6. **Space creation via API requires a manager.** `POST /api/spaces` rejects an empty `SpaceManagersTeamMembers` with "select either teams and/or users as managers". Always include at least one user ID. ## Best Practices 1. **One template per deployment pattern**, not per cloud. Use parameters to vary cloud-specific behaviour. 2. **Use step templates for reusable individual steps**, process templates for reusable multi-step workflows. 3. **Parameters should have sensible defaults** where possible — reduces friction for consuming projects. 4. **Use `TargetTags` parameter type** for Kubernetes target selection rather than hardcoding roles. 5. **Name templates with the action, not the technology**: "Deploy to Kubernetes" not "Helm Chart Deployer". 6. **Keep descriptions updated** — they appear in the UI when browsing templates. 7. **Process templates cannot reference the project's own Git repo** for scripts — use inline scripts or external URLs. 8. **Test templates** by creating a test project that consumes them before sharing widely. ## References - OCL Syntax: 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 - Process Templates: https://octopus.com/docs/platform-hub/templates/process-templates - Template Parameters: https://octopus.com/docs/platform-hub/templates/parameters - Publishing & Sharing: https://octopus.com/docs/platform-hub/templates/publishing-and-sharing - Best Practices: https://octopus.com/docs/platform-hub/templates/process-templates/best-practices - Troubleshooting: https://octopus.com/docs/platform-hub/templates/process-templates/troubleshooting - OCL Grammar (EBNF): https://github.com/OctopusDeploy/Ocl