Files
claude-foundations/best-practices/octopus-process-templates.md
Paul O'Reilly 6c0f2db169 Add Octopus Deploy Platform Hub knowledge base
New files:
- PLATFORMHUB.md: index for Platform Hub guidance
- platformhub/architecture.md: Git→PlatformHub→Projects model
- platformhub/ocl-syntax.md: complete OCL reference for templates
- platformhub/process-template-patterns.md: 5 proven patterns
- platformhub/gotchas.md: every error hit and how to fix it
- platformhub/api-reference.md: API vs UI capabilities
- best-practices/octopus-process-templates.md: consolidated best practices

Learned from building PlatformHub-Demo (30 microservices, 3 clouds).
Key discoveries: step templates are space-scoped (can't cross-reference),
worker_pool parameter is mandatory, publishing/sharing is UI-only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 09:54:09 +13:00

8.7 KiB

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/<slug>.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

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:

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:

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:

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):

action {
    action_type = "Octopus.Script"
    channels = ["non-prod"]          # only runs in non-prod channel
    properties = { ... }
}

Package References

# 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

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.

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