COPY and ADD heredoc bodies, COPY heredocs that contain shell scripts, COPY or ADD heredocs that contain
PowerShell scripts, and executable RUN heredoc bodies.
| Property | Value |
|---|---|
| Severity | Style |
| Category | Style |
| Default | Enabled |
| Auto-fix | Yes (safe) |
Description
This rule formats heredoc payloads that are copied into JSON, YAML, TOML, XML, or INI files. It detects structured file types from the heredoc destination path extension and uses the repository’s.editorconfig settings for indentation. YAML heredocs can also use max_line_length as a
preferred scalar wrapping width.
The rule also formats COPY heredocs as shell scripts when the first payload line is a recognized shell shebang, or when the destination path ends
in .sh and the payload has no shebang. Plain .sh payloads are parsed as POSIX shell. Unsupported shebangs are skipped instead of falling back to
the .sh extension.
The rule also formats RUN <<EOF heredocs whose body is executed as a shell script. It uses mvdan.cc/sh/v3, the same formatter library behind
shfmt, for Bash, POSIX shell, mksh, Bats, and zsh. Heredocs that are stdin payloads for another command, such as RUN cat <<EOF, are left alone.
cmd and unknown shebang bodies are skipped.
PowerShell heredocs are formatted with PSScriptAnalyzer’s Invoke-Formatter. This applies to COPY or ADD heredocs targeting .ps1, .psm1, or
.psd1 files, and to RUN <<EOF bodies when the active Dockerfile SHELL is PowerShell or the heredoc has a PowerShell shebang. tally starts the
PowerShell sidecar lazily, only when slow checks are enabled and a PowerShell heredoc actually needs formatting.
For structured payload EditorConfig lookup, tally resolves a virtual filename next to the Dockerfile using the destination basename. For example, a
heredoc in services/api/Dockerfile targeting /etc/app/config.yaml is matched as services/api/config.yaml, so selectors such as *.yaml and
config.yaml apply naturally.
COPY shell heredocs use the same destination-basename lookup, so a target such as /usr/local/bin/entrypoint.sh is matched as
entrypoint.sh and can use EditorConfig sections such as *.sh or entrypoint.sh.
For RUN shell heredocs, tally resolves a virtual filename next to the Dockerfile named Dockerfile.heredoc.<dialect>, such as
Dockerfile.heredoc.sh, Dockerfile.heredoc.bash, or Dockerfile.heredoc.zsh.
PowerShell heredocs use PSScriptAnalyzer’s code formatter with command-casing rewrites disabled, so formatting is stable across Linux, macOS, and
Windows hosts. They are skipped when slow checks are disabled and do not use EditorConfig today.
The formatter also runs as a final auto-fix pass. This means heredocs emitted by other rules, such as tally/prefer-copy-heredoc, are formatted in
the same --fix run when this rule is enabled.
Examples
Bad: COPY
Good: COPY
Bad: RUN
Good: RUN
Bad: COPY shell
Good: COPY shell
Bad: RUN PowerShell
Good: RUN PowerShell
Supported Types
| Extension | Format |
|---|---|
.json | JSON |
.yaml, .yml | YAML |
.toml | TOML |
.xml, .config, .xsd, .wsdl, .xsl, .xslt | XML |
.ini | INI |
Supported PowerShell Targets
| Extension | Format |
|---|---|
.ps1 | PowerShell script |
.psm1 | PowerShell script module |
.psd1 | PowerShell data file or module manifest |
Supported Shells
Shell formatting applies to executableRUN heredocs and to COPY heredocs with a recognized shell shebang. A COPY heredoc targeting .sh
without a shebang uses POSIX shell. PowerShell RUN heredocs use PSScriptAnalyzer instead of a shfmt dialect.
| Shell | Formatter dialect |
|---|---|
bash | Bash |
sh, dash, ash | POSIX shell |
mksh, ksh | mksh |
bats | Bats |
zsh | zsh |
Configuration
Default (no config needed):.editorconfig for indentation style and width, YAML scalar wrapping width, and
POSIX-style shell heredoc line width.
See EditorConfig integration for recommended Dockerfile settings and path resolution details.
The rule reads indent_style, indent_size, tab_width, and max_line_length. For YAML, max_line_length is used as a preferred scalar wrapping
width. For shell heredocs, it is used as a preferred command wrapping width; when unset or invalid, tally uses 100, and off disables this shell
line-width pass. This is not a hard maximum.
For POSIX-style shell heredocs, tally also reads shfmt-compatible EditorConfig booleans: binary_next_line, switch_case_indent, space_redirects,
keep_padding, function_next_line, simplify, and minify.
The rule does not currently interpret insert_final_newline, end_of_line, charset, or trim_trailing_whitespace for the virtual payload file.
Formatted heredoc bodies always end with exactly one newline before the heredoc terminator, and line endings follow the parent Dockerfile/fix
application rather than a separate payload setting. The current formatters do not emit incidental trailing whitespace, but tally does not run a
separate trailing-whitespace trim pass because whitespace can be payload data.