get-files.mjs strips trailing newline from committed file content
Summary
Every commit made through this action strips the trailing newline from each changed file's content, even when the source file on disk has one. This silently corrupts files over repeated runs (missing EOF newline, and risk of a later append-style edit landing on the same line as existing content).
Root cause
In src/get-files.mjs:
const content = await $`cat ${path}`
...
const item = {
path,
content: `${content}`, // <-- strips trailing newline(s)
...
}
content is a zx ProcessOutput. Interpolating it into a plain template literal (`${content}`) strips trailing newline characters from the captured stdout before it's sent as blob content to the GitHub Blobs API in src/commit.mjs.
Minimal repro (zx, independent of this repo):
import 'zx/globals'
$.verbose = false
const content = await $`cat f.yaml` // f.yaml ends with "line1\nline2\n"
console.log(JSON.stringify(`${content}`))
// => "line1\nline2" (trailing \n gone)
This strips all trailing newlines, not just one — a file ending in \n\n\n becomes line1\nline2 with none. So there's no way for a caller to work around this by padding the file before running the action; the fix needs to be in get-files.mjs.
Suggested fix
Read the file directly from disk instead of shelling out through cat + zx template-literal stringification, e.g.:
import { readFile } from 'node:fs/promises'
...
const raw = await readFile(path)
const item = {
path,
content: encoding === 'base64' ? raw.toString('base64') : raw.toString('utf-8'),
encoding,
...
}
This avoids the ProcessOutput → string coercion entirely and preserves file bytes exactly, including a trailing newline or the lack of one.
Verification
- Unit-level: test with files ending in
\n, \n\n, and no trailing newline; confirm produced content byte-for-byte matches the file on disk in all three cases.
- End-to-end: run the action against a test repo/branch on a file that ends with a newline, change a value, and confirm the committed file still ends with exactly one trailing newline (
git show <sha>:<path> | xxd | tail).
get-files.mjs strips trailing newline from committed file content
Summary
Every commit made through this action strips the trailing newline from each changed file's content, even when the source file on disk has one. This silently corrupts files over repeated runs (missing EOF newline, and risk of a later append-style edit landing on the same line as existing content).
Root cause
In
src/get-files.mjs:contentis a zxProcessOutput. Interpolating it into a plain template literal (`${content}`) strips trailing newline characters from the captured stdout before it's sent as blob content to the GitHub Blobs API insrc/commit.mjs.Minimal repro (zx, independent of this repo):
This strips all trailing newlines, not just one — a file ending in
\n\n\nbecomesline1\nline2with none. So there's no way for a caller to work around this by padding the file before running the action; the fix needs to be inget-files.mjs.Suggested fix
Read the file directly from disk instead of shelling out through
cat+ zx template-literal stringification, e.g.:This avoids the
ProcessOutput→ string coercion entirely and preserves file bytes exactly, including a trailing newline or the lack of one.Verification
\n,\n\n, and no trailing newline; confirm producedcontentbyte-for-byte matches the file on disk in all three cases.git show <sha>:<path> | xxd | tail).