Skip to content

WIP: Multiline shell - #116

Open
m-ildefons wants to merge 1 commit into
hadolint:masterfrom
m-ildefons:wip/multiline-shell
Open

WIP: Multiline shell#116
m-ildefons wants to merge 1 commit into
hadolint:masterfrom
m-ildefons:wip/multiline-shell

Conversation

@m-ildefons

Copy link
Copy Markdown
Member

What problem does this PR address

Improve how line-breaks are represented in the AST to allow Hadolint to correctly calculate the position of Shellcheck-warnings.

related-to: hadolint/hadolint#891
related-to: hadolint/hadolint#285
related-to: hadolint/hadolint#251

How is this PR supposed to work

Parse shell commands into a list of lines, separated at escaped line breaks, which can be re-assembled to a shell script.
This would later allow to re-construct the correct line within the Dockerfile where an error happens, because the line in the shell script would indicate the correct position relative to the line of the instruction in the Dockerfile.

E.g.:

RUN foo \                              # line 13
    bar && [ -e error_here]            # line 14

would parse into

Run ( RunArgs ( ArgumentsText ["foo \\", " bar && [ -e error]"] ) RunFlags ... )

form this the shell script could be reconstructed as:

foo \                                   # line 1 of shell script
 bar && [ -e error_here]                # line 2 of shell script

With this script, the commands can be checked e.g. with Shellcheck, which will find an error on line 2.
This error can now be correctly associated with the line in the dockerfile, beause the output of Shellcheck would contain the line-number relative to the RUN instruction.
In this case, the error line would be calculated as

$line_of_RUN_instruction + $relative_line_in_shell - 1, i.e.:

13 + 2 - 1 = 14

This would yield the correct line where the error happens.

How to test this PR

There are unit-tests included to make sure this change produces the expected AST. However to reap the benefits of this change, there are also some changes required in Hadolint as well.
To test that, a custom build of Hadolint with those changes must be made:

  1. Set up a separate workspace
mkdir -p ~/tmp/hadolint-multiline
cd ~/tmp/hadolint-multiline
  1. Clone the modified hadolint and language-docker repositories
git clone git@github.com:m-ildefons/language-docker.git
cd ~/tmp/hadolint-multiline/language-docker
git checkout wip/multiline-shell

git clone git@github.com:m-ildefons/hadolint.git
cd ~/tmp/hadolint-multiline/hadolint
git checkout wip/multiline-shell
  1. Build Hadolint
cabal build exe:hadolint
cp $(cabal list-bin exe:hadolint) ~/.local/bin/hadolint-multiline
  1. Test custom Hadolint build with Dockerfiles

E.g. This Dockerfile should show Shellcheck warnings on all lines with $warning

FROM debian:trixie

RUN foobar \
    barfoo \
    foofoo-$warning \
    foofoobarbar \
    barbar \
    foobar-$warning


RUN <<EOF
#!/bin/bash

foobar
barfoo
foofoo-$warning

barbar

foobar-$warning
EOF
Normal Hadolint - Warnings only in the line where the Docker instruction is rooted Screenshot at 2026-08-12 15-50-35
Custom Hadolint build with this change - Warnings at the line where the problem is Screenshot at 2026-08-12 15-50-57

This is experimental. Parse shell commands into a list of lines,
separated at escaped line breaks, which can be re-assembled to a shell
script.
This would later allow to re-construct the correct line within the
Dockerfile where an error happens, because the line in the shell script
would indicate the correct position relative to the first escaped line
break in the Dockerfile.

E.g.:

```dockerfile
RUN foo \                              # line 13
    bar && [ -e error]                 # line 14
```

would parse into

Run (RunArgs (ArgumentsLines ["foo", " bar && [ -e error]"]) RunFlags ...)

form this the shell script could be reconstructed as:

```shell
foo \                                   # line 1
bar && [ -e error]                      # line 2
```

With this script, the commands can be checked e.g. with Shellcheck,
which will find an error on line 2.
This error can now be correctly associated with the line in the
dockerfile, beause the output of Shellcheck would contain the
line-number relative to the RUN instruction.
In this case, the error line would be calculated as

$line_of_RUN_instruction + $relative_line_in_shell - 1, i.e.:

13 + 2 - 1 = 14

This would yield the correct line where the error happens.

Signed-off-by: Moritz Röhrich <moritz@ildefons.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant