Migrates 20 topic files from claude-foundations/best-practices/ to this standalone repo. Adds BESTPRACTICES.md index, CLAUDE.md conventions, and updated README.md. Container agents clone this repo to /best-practices. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
222 lines
8.7 KiB
Markdown
222 lines
8.7 KiB
Markdown
# 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
|
|
|
|
```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
|
|
|
|
## 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
|
|
|
|
- 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
|