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>
277 lines
8.3 KiB
Markdown
277 lines
8.3 KiB
Markdown
# 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)
|