Files
claude-foundations/platformhub/ocl-syntax.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.3 KiB

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

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

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

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)

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

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:

$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']

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

Octopus.Action.GitRepository.FilePathFilters = "#{{yaml_path}}"

Output Variables

Set output variables from scripts for use in later steps:

Write-Host "##octopus[setVariable name='CoveragePercent' value='87']"

Read in subsequent steps:

$coverage = $OctopusParameters['Octopus.Action[run-unit-tests].Output.CoveragePercent']

Channel Scoping

Scope steps to specific channels (for dual-image patterns):

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

Environment Scoping

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