Description
Suggests converting multi-command RUN instructions to heredoc syntax for better readability. This rule targets Dockerfile here-documents withRUN, which are supported by BuildKit syntax.
Shell-specific heredoc bodies are supported too:
- POSIX shells keep the usual multi-line heredoc body with
set -eand optionalset -o pipefail - PowerShell heredocs use a multi-line body with
$ErrorActionPreference = 'Stop'plus explicit guards between commands. This applies topowershellon Windows andpwshon cross-platform images. cmd.exeheredocs are supported, but real WCOW builds only executed chained bodies reliably when the body stayed on one logical line, so the fixer emits a grouped single-line(...)command list inside the heredoc
- Multiple consecutive RUN instructions that could be combined
- Single RUN with chained commands via
&&(3+ commands by default)
Why heredoc?
Heredoc syntax for RUN instructions offers:- Readability: Each command on its own line, no
&&or\clutter - Maintainability: Easy to add, remove, or reorder commands
- Debugging: Clear line numbers in error messages
Examples
Before (violation)
After (fixed with —fix)
Another real-life example
Why set -e?
Heredocs don’t stop on error by default - only the exit code of the last command matters. Adding set -e preserves the fail-fast behavior of &&
chains.
See moby/buildkit#2722 for details.
For non-POSIX shells, the fixer preserves the same intent with shell-native
behavior instead of set -e:
- PowerShell gets
$ErrorActionPreference = 'Stop'and$PSNativeCommandUseErrorActionPreference = $true cmd.exekeeps the original&&semantics inside a grouped command block
Options
Configuration
Rule Coordination
When this rule is enabled,hadolint/DL3003 (cd → WORKDIR) will skip generating fixes for commands that are heredoc candidates, allowing heredoc
conversion to handle cd correctly within the script.
On Windows, this rule also collaborates with tally/powershell/prefer-shell-instruction:
- if repeated
RUN powershell ...orRUN pwsh ...wrappers are first normalized into a PowerShellSHELL, this rule will then see the rewrittenRUNinstructions under the effective PowerShell shell - that lets a
cmd-styleRUN powershell ... && ...sequence become a proper PowerShell heredoc instead of falling back to acmd.exeheredoc body - the same pass can also absorb immediately following PowerShell-safe
RUNinstructions, so a stage can end up with one larger PowerShell heredoc after theSHELLrewrite