Skip to content

fix: enforce LF line endings for shell scripts, gradlew, KEYS#15620

Closed
jamesfredley wants to merge 1 commit into8.0.xfrom
fix/eol-normalization
Closed

fix: enforce LF line endings for shell scripts, gradlew, KEYS#15620
jamesfredley wants to merge 1 commit into8.0.xfrom
fix/eol-normalization

Conversation

@jamesfredley
Copy link
Copy Markdown
Contributor

Summary

Pin the line endings of shell scripts, gradlew, KEYS, and the Dockerfile to LF on every platform, and add a defensive sed strip step in etc/bin/Dockerfile, so the release verification container is reproducible from a Windows committer's checkout.

Why

There is no .gitattributes in the repo today. With Git for Windows' default core.autocrlf=true, every Windows checkout converts these files from LF to CRLF in the working tree. The Dockerfile's ADD then preserves the CRLF into the image, which produces three independent failures during release verification:

  1. The Linux kernel refuses to execute scripts with bash\r in the shebang, so gradlew and every verify-*.sh script fail with cannot execute: required file not found / /usr/bin/env: 'bash\r': No such file or directory.
  2. verify-keys.sh shasum-512s the in-tree KEYS file and compares against the canonical copy at https://dist.apache.org/repos/dist/release/grails/KEYS. The two byte-streams differ by exactly one \r per line (52 bytes total) and the comparison fails even though the content is byte-identical after normalization.
  3. By extension, verify.sh aborts at its first step (verify-keys.sh) on any Windows committer's machine. The container documented in RELEASE.md is unusable as-is.

CI on ubuntu-latest and any Linux/macOS verifier are unaffected. The bug is only visible to a Windows committer because git's checkout-time conversion is the layer that introduces the corruption.

Why fix this at the .gitattributes layer

.gitattributes is the only mechanism in the repo that operates at git's working-tree write path. Other code-style mechanisms either don't run at the right time or don't cover the right files:

Tool Audits *.sh / gradlew / KEYS? Runs at checkout?
.editorconfig (existing - groovy/java only) No No (editor-time)
Checkstyle / codeStyle task No (Java/Groovy only) No (build-time)
CodeNarc No (Groovy only; LineEnding rule not enabled) No (build-time)
.gitattributes (this PR) Yes Yes

Changes

.gitattributes (new)

  • * text=auto - sane default; git auto-detects text vs binary, stores text as LF in the index
  • *.sh, gradlew, KEYS, Dockerfile, *.properties -> text eol=lf (must be LF on Linux verifier and CI)
  • *.bat, *.cmd, gradlew.bat -> text eol=crlf (must be CRLF on Windows)
  • Common binary types (*.jar, *.zip, *.png, *.pdf, *.gpg, *.keystore, ...) marked binary so git never normalizes them

etc/bin/Dockerfile

Add a RUN sed -i 's/\r$//' step after the ADD lines, scoped to *.sh, gradlew, KEYS, and *.properties. This is belt-and-braces: even if a committer's working tree still has CRLF (because their local checkout predates this PR and they have not re-checked-out / renormalized), the image they build will still be correct.

Index impact

Verified ahead of time:

$ git ls-files --eol gradlew etc/bin/verify.sh KEYS gradlew.bat etc/bin/Dockerfile
i/lf    w/crlf  attr/  KEYS
i/lf    w/crlf  attr/  etc/bin/Dockerfile
i/lf    w/crlf  attr/  etc/bin/verify.sh
i/lf    w/crlf  attr/  gradlew
i/crlf  w/crlf  attr/  gradlew.bat

Every affected file is already LF in the index. Only the working tree is CRLF on Windows. This PR therefore does not require git add --renormalize . and does not produce any blob churn - it only changes what git checkout writes to disk on the next checkout.

Local verification

Done on a Windows machine with core.autocrlf=true:

  • Before this PR: docker build -f etc/bin/Dockerfile . succeeds, but inside the container gradlew --version, verify.sh v..., and verify-keys.sh all fail with the bash\r / hash-mismatch errors described above.
  • After this PR (with the RUN sed step alone, since no re-checkout was needed locally): the image's gradlew --version succeeds and downloads Gradle 9.4.1, verify.sh reaches its arg-validation step, and verify-keys.sh passes the byte-for-byte SVN comparison against dist.apache.org/repos/dist/release/grails/KEYS.

Related

Companion to #15619 (docs: update RELEASE.md examples for 8.0.0-M1). With both PRs merged, the container verification flow on 8.0.x is ready for the upcoming 8.0.0-M1 milestone release on every platform.

The release verification flow runs in a Linux container built from
etc/bin/Dockerfile, but the repository had no .gitattributes. With
Git for Windows' default core.autocrlf=true, every Windows checkout
converts gradlew, etc/bin/*.sh, the Dockerfile, and the KEYS file
from LF to CRLF in the working tree. The Dockerfile's ADD then
preserves those CRLFs into the image, with three failure modes:

1. The Linux kernel refuses to execute scripts with `bash\r` in the
   shebang, so gradlew and every verify-*.sh script fails with
   "cannot execute: required file not found".
2. verify-keys.sh hashes the in-tree KEYS file and compares against
   https://dist.apache.org/repos/dist/release/grails/KEYS, which is
   stored as LF. The hashes mismatch even though the content is
   byte-identical after line-ending normalization.
3. By extension, verify.sh aborts at its first step on any Windows
   committer's machine.

Fix at the right layer (git's working-tree write path):

- Add .gitattributes pinning *.sh, gradlew, KEYS, Dockerfile, and
  *.properties to eol=lf, while keeping *.bat / *.cmd / gradlew.bat
  as eol=crlf and marking common binary types as binary so git
  never tries to normalize them. Default `* text=auto` lets git
  auto-detect everything else.
- Add a defensive sed-strip step in etc/bin/Dockerfile after the
  ADD lines, so even if a committer feeds a CRLF-corrupted build
  context (existing local checkout under autocrlf=true), the image
  still ends up with LF scripts.

Existing index content is unchanged: every affected file is already
stored as LF in the index. This commit only changes what `git
checkout` writes to the working tree on Windows and adds belt-and-
braces normalization at image-build time.

CI on ubuntu-latest is unaffected. Linux/macOS verifiers are
unaffected. Windows verifiers can now run the container build flow
documented in RELEASE.md without manual workarounds.

Assisted-by: claude-code:claude-opus-4-7
Copilot AI review requested due to automatic review settings May 2, 2026 13:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@testlens-app
Copy link
Copy Markdown

testlens-app Bot commented May 2, 2026

✅ All tests passed ✅

🏷️ Commit: 0cc3558
▶️ Tests: 19250 executed
⚪️ Checks: 39/39 completed


Learn more about TestLens at testlens.app.

Comment thread etc/bin/Dockerfile
# still feed CRLF into the build context. Linux refuses scripts with bash\r
# shebangs and verify-keys.sh would fail the byte-for-byte SVN comparison.
# Strip CRs from any text file that must be LF on Linux.
RUN find /home/groovy/scripts -type f \( -name '*.sh' -o -name 'gradlew' -o -name 'KEYS' -o -name '*.properties' \) -exec sed -i 's/\r$//' {} \;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is really only for windows? I have never had this problem on a mac

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100%, I had fixed it a long time ago, but now have 4 copies of grails-core across a few machines and ran into it again.

@bito-code-review
Copy link
Copy Markdown

The change adds defensive line-ending normalization in the Dockerfile to strip carriage returns (CR) from scripts and related files, addressing potential CRLF issues from Windows users despite .gitattributes settings. Macs use LF by default, so this problem is less common there, but the fix ensures compatibility across platforms.

@jamesfredley jamesfredley changed the base branch from 8.0.x to 7.0.x May 2, 2026 15:18
@jamesfredley jamesfredley changed the base branch from 7.0.x to 8.0.x May 2, 2026 15:20
@jamesfredley
Copy link
Copy Markdown
Contributor Author

Replaced by #15622 so we have this change on 7.0.x -> 8.0.x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants